]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Move calendar handling out-of-process
authorDavid Zeuthen <davidz@redhat.com>
Fri, 25 Feb 2011 22:42:25 +0000 (17:42 -0500)
committerDavid Zeuthen <davidz@redhat.com>
Mon, 28 Feb 2011 21:08:18 +0000 (16:08 -0500)
Unfortunately the evolution-data-server client-side libraries seem to
block the calling thread. This is a major problem as we must never
ever block the main thread (doing so causes animations to flicker
etc.). In the worst case, this problem causes login to hang (without
falling back to fall-back mode) and in the best case it slows down
login until a network connection is acquired.

Additionally, in order to sanely use these evolution-data-server
libraries, GConf has to be involved and GConf is not thread-safe. So
it's not really feasible just moving the code to a separate
thread. Therefore, move all calendar IO out of process and use a
simple (and private) D-Bus interface for the shell to communicate with
the out-of-process helper.

For simplification, remove existing in-process code since internal
interfaces have been slightly revised. This means that the shell is no
longer using any native code for drawing the calendar dropdown.

https://bugzilla.gnome.org/show_bug.cgi?id=641396

Signed-off-by: David Zeuthen <davidz@redhat.com>
24 files changed:
configure.ac
js/ui/calendar.js
js/ui/dateMenu.js
js/ui/main.js
src/Makefile-calendar-client.am [deleted file]
src/Makefile-calendar-server.am [new file with mode: 0644]
src/Makefile.am
src/calendar-client/README [deleted file]
src/calendar-client/calendar-client.c [deleted file]
src/calendar-client/calendar-client.h [deleted file]
src/calendar-client/calendar-debug.h [deleted file]
src/calendar-client/calendar-sources.c [deleted file]
src/calendar-client/calendar-sources.h [deleted file]
src/calendar-server/README [new file with mode: 0644]
src/calendar-server/calendar-debug.h [new file with mode: 0644]
src/calendar-server/calendar-sources.c [new file with mode: 0644]
src/calendar-server/calendar-sources.h [new file with mode: 0644]
src/calendar-server/gnome-shell-calendar-server.c [new file with mode: 0644]
src/calendar-server/org.gnome.Shell.CalendarServer.service.in [new file with mode: 0644]
src/gnome-shell.in
src/shell-evolution-event-source.c [deleted file]
src/shell-evolution-event-source.h [deleted file]
src/shell-global.c
src/shell-global.h

index c3dc6397e03b81ea01f774c2b605a932ceb3ddd3..8155bae4ac756b93e909b965184f292bea48b045 100644 (file)
@@ -66,10 +66,10 @@ GJS_MIN_VERSION=0.7.11
 MUTTER_MIN_VERSION=2.91.90
 GTK_MIN_VERSION=3.0.0
 GIO_MIN_VERSION=2.25.9
-LIBECAL_REQUIRED=1.6.0
-LIBEDATASERVER_REQUIRED=1.2.0
-LIBEDATASERVERUI2_REQUIRED=1.2.0
-LIBEDATASERVERUI3_REQUIRED=2.91.6
+LIBECAL_MIN_VERSION=1.6.0
+LIBEDATASERVER_MIN_VERSION=1.2.0
+LIBEDATASERVERUI2_MIN_VERSION=1.2.0
+LIBEDATASERVERUI3_MIN_VERSION=2.91.6
 TELEPATHY_GLIB_MIN_VERSION=0.13.12
 POLKIT_MIN_VERSION=0.100
 
@@ -125,12 +125,12 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
 # Default to libedataserverui-3.0, but allow falling back to 1.2
 PKG_CHECK_EXISTS(libedataserverui-3.0,
                  [EDS_API=3.0
-                  LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI3_REQUIRED],
+                  LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI3_MIN_VERSION],
                  [EDS_API=1.2
-                  LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI2_REQUIRED])
-PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-$EDS_API >= $LIBEDATASERVERUI_REQUIRED)
-AC_SUBST(LIBECAL_CFLAGS)
-AC_SUBST(LIBECAL_LIBS)
+                  LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI2_MIN_VERSION])
+PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-$EDS_API >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
+AC_SUBST(CALENDAR_SERVER_CFLAGS)
+AC_SUBST(CALENDAR_SERVER_LIBS)
 
 MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
 # FIXME: metacity-plugins.pc should point directly to its .gir file
index 643a66a57d899b472fb239cf7e056c9841e9c5eb..abedb2650288db2b61d7d64e8a52ed32e7df4262 100644 (file)
@@ -1,5 +1,6 @@
 /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 
+const DBus = imports.dbus;
 const Clutter = imports.gi.Clutter;
 const Gio = imports.gi.Gio;
 const Lang = imports.lang;
@@ -158,13 +159,14 @@ function _getEventDayAbbreviation(dayNumber) {
 
 // Abstraction for an appointment/event in a calendar
 
-function CalendarEvent(date, summary, allDay) {
-    this._init(date, summary, allDay);
+function CalendarEvent(date, end, summary, allDay) {
+    this._init(date, end, summary, allDay);
 }
 
 CalendarEvent.prototype = {
-    _init: function(date, summary, allDay) {
+    _init: function(date, end, summary, allDay) {
         this.date = date;
+        this.end = end;
         this.summary = summary;
         this.allDay = allDay;
     }
@@ -196,139 +198,136 @@ EmptyEventSource.prototype = {
 };
 Signals.addSignalMethods(EmptyEventSource.prototype);
 
-// Second, wrap native Evolution event source
-function EvolutionEventSource() {
+const CalendarServerIface = {
+    name: 'org.gnome.Shell.CalendarServer',
+    methods: [{ name: 'GetEvents',
+                inSignature: 'xxb',
+                outSignature: 'a(sssbxxa{sv})' }],
+    signals: [{ name: 'Changed',
+                inSignature: '' }]
+};
+
+const CalendarServer = function () {
     this._init();
-}
+};
 
-EvolutionEventSource.prototype = {
-    _init: function() {
-        this._native = new Shell.EvolutionEventSource();
-        this._native.connect('changed', Lang.bind(this, function() {
-            this.emit('changed');
-        }));
-    },
+CalendarServer.prototype = {
+     _init: function() {
+         DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer');
+     }
+};
 
-    requestRange: function(begin, end) {
-        this._native.request_range(begin.getTime(), end.getTime());
-    },
+DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface);
 
-    getEvents: function(begin, end) {
-        let result = [];
-        let nativeEvents = this._native.get_events(begin.getTime(), end.getTime());
-        for (let n = 0; n < nativeEvents.length; n++) {
-            let nativeEvent = nativeEvents[n];
-            result.push(new CalendarEvent(new Date(nativeEvent.msec_begin), nativeEvent.summary, nativeEvent.all_day));
-        }
-        return result;
-    },
+// an implementation that reads data from a session bus service
+function DBusEventSource(owner) {
+    this._init(owner);
+}
 
-    hasEvents: function(day) {
-        let dayBegin = _getBeginningOfDay(day);
-        let dayEnd = _getEndOfDay(day);
+function _datesEqual(a, b) {
+    if (a < b)
+        return false;
+    else if (a > b)
+        return false;
+    return true;
+}
 
-        let events = this.getEvents(dayBegin, dayEnd);
+function _dateIntervalsOverlap(a0, a1, b0, b1)
+{
+    if (a1 <= b0)
+        return false;
+    else if (b1 <= a0)
+        return false;
+    else
+        return true;
+}
 
-        if (events.length == 0)
-            return false;
 
-        return true;
-    }
-};
-Signals.addSignalMethods(EvolutionEventSource.prototype);
+DBusEventSource.prototype = {
+    _init: function(owner) {
+        this._resetCache();
 
-// Finally, an implementation with fake events
-function FakeEventSource() {
-    this._init();
-}
+        this._dbusProxy = new CalendarServer(owner);
+        this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
 
-FakeEventSource.prototype = {
-    _init: function() {
+        DBus.session.watch_name('org.gnome.Shell.CalendarServer',
+                                false, // do not launch a name-owner if none exists
+                                Lang.bind(this, this._onNameAppeared),
+                                Lang.bind(this, this._onNameVanished));
+    },
 
-        this._fakeEvents = [];
+    _resetCache: function() {
+        this._events = [];
+        this._lastRequestBegin = null;
+        this._lastRequestEnd = null;
+    },
 
-        // Generate fake events
-        //
-        let midnightToday = _getBeginningOfDay(new Date());
-        let summary = '';
-
-        // '10-oclock pow-wow' is an event occuring IN THE PAST every four days at 10am
-        for (let n = 0; n < 10; n++) {
-            let t = new Date(midnightToday.getTime() - n * 4 * 86400 * 1000);
-            t.setHours(10);
-            summary = '10-oclock pow-wow (n=' + n + ')';
-            this._fakeEvents.push(new CalendarEvent(t, summary, false));
-        }
+    _onNameAppeared: function(owner) {
+        this._resetCache();
+        this._loadEvents(true);
+    },
 
-        // '11-oclock thing' is an event occuring every three days at 11am
-        for (let n = 0; n < 10; n++) {
-            let t = new Date(midnightToday.getTime() + n * 3 * 86400 * 1000);
-            t.setHours(11);
-            summary = '11-oclock thing (n=' + n + ')';
-            this._fakeEvents.push(new CalendarEvent(t, summary, false));
-        }
+    _onNameVanished: function(oldOwner) {
+        this._resetCache();
+        this.emit('changed');
+    },
 
-        // 'Weekly Meeting' is an event occuring every seven days at 1:45pm (two days displaced)
-        for (let n = 0; n < 5; n++) {
-            let t = new Date(midnightToday.getTime() + (n * 7 + 2) * 86400 * 1000);
-            t.setHours(13);
-            t.setMinutes(45);
-            summary = 'Weekly Meeting (n=' + n + ')';
-            this._fakeEvents.push(new CalendarEvent(t, summary, false));
-        }
+    _onChanged: function() {
+        this._loadEvents(false);
+    },
 
-        // 'Fun All Day' is an all-day event occuring every fortnight (three days displayed)
-        for (let n = 0; n < 10; n++) {
-            let t = new Date(midnightToday.getTime() + (n * 14 + 3) * 86400 * 1000);
-            summary = 'Fun All Day (n=' + n + ')';
-            this._fakeEvents.push(new CalendarEvent(t, summary, true));
+    _onEventsReceived: function(appointments) {
+        let newEvents = [];
+        if (appointments != null) {
+            for (let n = 0; n < appointments.length; n++) {
+                let a = appointments[n];
+                let date = new Date(a[4] * 1000);
+                let end = new Date(a[5] * 1000);
+                let summary = a[1];
+                let allDay = a[3];
+                let event = new CalendarEvent(date, end, summary, allDay);
+                newEvents.push(event);
+            }
+            newEvents.sort(function(event1, event2) {
+                return event1.date.getTime() - event2.date.getTime();
+            });
         }
 
-        // 'Get Married' is an event that actually reflects reality (Dec 4, 2010) :-)
-        this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 4, 16, 0), 'Get Married', false));
-
-        // ditto for 'NE Patriots vs NY Jets'
-        this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 6, 20, 30), 'NE Patriots vs NY Jets', false));
-
-        // An event for tomorrow @6:30pm that is added/removed every five
-        // seconds (to check that the ::changed signal works)
-        let transientEventDate = new Date(midnightToday.getTime() + 86400 * 1000);
-        transientEventDate.setHours(18);
-        transientEventDate.setMinutes(30);
-        transientEventDate.setSeconds(0);
-        Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
-        this._includeTransientEvent = false;
-        this._transientEvent = new CalendarEvent(transientEventDate, 'A Transient Event', false);
-        this._transientEventCounter = 1;
+        this._events = newEvents;
+        this.emit('changed');
     },
 
-    _updateTransientEvent: function() {
-        this._includeTransientEvent = !this._includeTransientEvent;
-        this._transientEventCounter = this._transientEventCounter + 1;
-        this._transientEvent.summary = 'A Transient Event (' + this._transientEventCounter + ')';
-        this.emit('changed');
-        Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
+    _loadEvents: function(forceReload) {
+        if (this._curRequestBegin && this._curRequestEnd){
+            let callFlags = 0;
+            if (forceReload)
+                callFlags |= DBus.CALL_FLAG_START;
+            this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
+                                            this._curRequestEnd.getTime() / 1000,
+                                            forceReload,
+                                            Lang.bind(this, this._onEventsReceived),
+                                            callFlags);
+        }
     },
 
-    requestRange: function(begin, end) {
+    requestRange: function(begin, end, forceReload) {
+        if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
+            this._lastRequestBegin = begin;
+            this._lastRequestEnd = end;
+            this._curRequestBegin = begin;
+            this._curRequestEnd = end;
+            this._loadEvents(forceReload);
+        }
     },
 
     getEvents: function(begin, end) {
         let result = [];
-        //log('begin:' + begin);
-        //log('end:  ' + end);
-        for(let n = 0; n < this._fakeEvents.length; n++) {
-            let event = this._fakeEvents[n];
-            if (event.date >= begin && event.date <= end) {
+        for(let n = 0; n < this._events.length; n++) {
+            let event = this._events[n];
+            if (_dateIntervalsOverlap (event.date, event.end, begin, end)) {
                 result.push(event);
             }
-            //log('when:' + event.date + ' summary:' + event.summary);
         }
-        if (this._includeTransientEvent && this._transientEvent.date >= begin && this._transientEvent.date <= end)
-            result.push(this._transientEvent);
-        result.sort(function(event1, event2) {
-            return event1.date.getTime() - event2.date.getTime();
-        });
         return result;
     },
 
@@ -343,9 +342,8 @@ FakeEventSource.prototype = {
 
         return true;
     }
-
 };
-Signals.addSignalMethods(FakeEventSource.prototype);
+Signals.addSignalMethods(DBusEventSource.prototype);
 
 // Calendar:
 // @eventSource: is an object implementing the EventSource API, e.g. the
@@ -358,7 +356,10 @@ Calendar.prototype = {
     _init: function(eventSource) {
         this._eventSource = eventSource;
 
-        this._eventSource.connect('changed', Lang.bind(this, this._update));
+        this._eventSource.connect('changed', Lang.bind(this,
+                                                       function() {
+                                                           this._update(false);
+                                                       }));
 
         // FIXME: This is actually the fallback method for GTK+ for the week start;
         // GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
@@ -407,15 +408,17 @@ Calendar.prototype = {
                            Lang.bind(this, this._onScroll));
 
         this._buildHeader ();
-        this._update();
     },
 
     // Sets the calendar to show a specific date
-    setDate: function(date) {
+    setDate: function(date, forceReload) {
         if (!_sameDay(date, this._selectedDate)) {
             this._selectedDate = date;
-            this._update();
+            this._update(forceReload);
             this.emit('selected-date-changed', new Date(this._selectedDate));
+        } else {
+            if (forceReload)
+                this._update(forceReload);
         }
     },
 
@@ -510,7 +513,7 @@ Calendar.prototype = {
             }
         }
 
-        this.setDate(newDate);
+        this.setDate(newDate, false);
    },
 
    _onNextMonthButtonClicked: function() {
@@ -532,16 +535,16 @@ Calendar.prototype = {
             }
         }
 
-        this.setDate(newDate);
+       this.setDate(newDate, false);
     },
 
     _onSettingsChange: function() {
         this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
         this._buildHeader();
-        this._update();
+        this._update(false);
     },
 
-    _update: function() {
+    _update: function(forceReload) {
         let now = new Date();
 
         if (_sameYear(this._selectedDate, now))
@@ -570,7 +573,7 @@ Calendar.prototype = {
             let iterStr = iter.toUTCString();
             button.connect('clicked', Lang.bind(this, function() {
                 let newlySelectedDate = new Date(iterStr);
-                this.setDate(newlySelectedDate);
+                this.setDate(newlySelectedDate, false);
             }));
 
             let hasEvents = this._eventSource.hasEvents(iter);
@@ -620,7 +623,7 @@ Calendar.prototype = {
         }
         // Signal to the event source that we are interested in events
         // only from this date range
-        this._eventSource.requestRange(beginDate, iter);
+        this._eventSource.requestRange(beginDate, iter, forceReload);
     }
 };
 
@@ -698,7 +701,7 @@ EventsList.prototype = {
         if (events.length == 0 && showNothingScheduled) {
             let now = new Date();
             /* Translators: Text to show if there are no events */
-            let nothingEvent = new CalendarEvent(now, _("Nothing Scheduled"), true);
+            let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
             let timeString = _formatEventTime(nothingEvent, clockFormat);
             this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
         }
index 1f193aa7c4489b711162f65bebda97624089a160..6dee534b6ebd2e3dd6ab99702d35a4875bf7c842 100644 (file)
@@ -52,9 +52,7 @@ DateMenuButton.prototype = {
         let hbox;
         let vbox;
 
-        //this._eventSource = new Calendar.EmptyEventSource();
-        //this._eventSource = new Calendar.FakeEventSource();
-        this._eventSource = new Calendar.EvolutionEventSource();
+        this._eventSource = new Calendar.DBusEventSource();
 
         let menuAlignment = 0.25;
         if (St.Widget.get_default_direction() == St.TextDirection.RTL)
@@ -117,7 +115,20 @@ DateMenuButton.prototype = {
         this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
             if (isOpen) {
                 let now = new Date();
-                this._calendar.setDate(now);
+                /* Passing true to setDate() forces events to be reloaded. We
+                 * want this behavior, because
+                 *
+                 *   o It will cause activation of the calendar server which is
+                 *     useful if it has crashed
+                 *
+                 *   o It will cause the calendar server to reload events which
+                 *     is useful if dynamic updates are not supported or not
+                 *     properly working
+                 *
+                 * Since this only happens when the menu is opened, the cost
+                 * isn't very big.
+                 */
+                this._calendar.setDate(now, true);
                 // No need to update this._eventList as ::selected-date-changed
                 // signal will fire
             }
index 5c6b952d0005f47481d602c1a680c9a964896860..873980d8ca68ef9c35348dc61a38754e6dde6e27 100644 (file)
@@ -95,6 +95,10 @@ function start() {
     // back into sync ones.
     DBus.session.flush();
 
+    // Load the calendar server. Note that we are careful about
+    // not loading any events until the user presses the clock
+    global.launch_calendar_server();
+
     Environment.init();
 
     // Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
diff --git a/src/Makefile-calendar-client.am b/src/Makefile-calendar-client.am
deleted file mode 100644 (file)
index cac046f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-
-noinst_LTLIBRARIES += libcalendar-client.la
-
-libcalendar_client_la_SOURCES =                                                        \
-       calendar-client/calendar-client.h       calendar-client/calendar-client.c       \
-       calendar-client/calendar-debug.h                                                \
-       calendar-client/calendar-sources.c      calendar-client/calendar-sources.h      \
-       $(NULL)
-
-libcalendar_client_la_CFLAGS =                         \
-       -I$(top_srcdir)/src                     \
-       -DPREFIX=\""$(prefix)"\"                \
-       -DLIBDIR=\""$(libdir)"\"                \
-       -DDATADIR=\""$(datadir)"\"              \
-       -DG_DISABLE_DEPRECATED                  \
-       -DG_LOG_DOMAIN=\"CalendarClient\"       \
-       $(LIBECAL_CFLAGS)                       \
-       $(NULL)
-
-libcalendar_client_la_LIBADD = $(LIBECAL_LIBS)
-
-EXTRA_DIST += calendar-client/README
diff --git a/src/Makefile-calendar-server.am b/src/Makefile-calendar-server.am
new file mode 100644 (file)
index 0000000..e617668
--- /dev/null
@@ -0,0 +1,34 @@
+
+servicedir       = $(datadir)/dbus-1/services
+service_in_files = calendar-server/org.gnome.Shell.CalendarServer.service.in
+service_DATA     = $(service_in_files:.service.in=.service)
+
+$(service_DATA): $(service_in_files) Makefile
+       @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@.tmp && mv $@.tmp $@
+
+libexec_PROGRAMS += gnome-shell-calendar-server
+
+gnome_shell_calendar_server_SOURCES =                                                          \
+       calendar-server/calendar-debug.h                                                        \
+       calendar-server/calendar-sources.c              calendar-server/calendar-sources.h      \
+       calendar-server/gnome-shell-calendar-server.c                                           \
+       $(NULL)
+
+gnome_shell_calendar_server_CFLAGS =           \
+       -I$(top_srcdir)/src                     \
+       -DPREFIX=\""$(prefix)"\"                \
+       -DLIBDIR=\""$(libdir)"\"                \
+       -DDATADIR=\""$(datadir)"\"              \
+       -DG_DISABLE_DEPRECATED                  \
+       -DG_LOG_DOMAIN=\"ShellCalendarServer\"  \
+       $(CALENDAR_SERVER_CFLAGS)               \
+       $(NULL)
+
+gnome_shell_calendar_server_LDFLAGS =          \
+       $(CALENDAR_SERVER_LIBS)                 \
+       $(NULL)
+
+EXTRA_DIST +=                                                    \
+       calendar-server/README                                    \
+       calendar-server/org.gnome.Shell.CalendarServer.service.in \
+       $(NULL)
index ea12a2b9003bed5190dcdb8077340203c30922a0..71cb018119470b2226146457f2cd99737b744f02 100644 (file)
@@ -27,13 +27,14 @@ include Makefile-gdmuser.am
 include Makefile-st.am
 include Makefile-tray.am
 include Makefile-gvc.am
-include Makefile-calendar-client.am
+include Makefile-calendar-server.am
 
 gnome_shell_cflags =                           \
        $(MUTTER_PLUGIN_CFLAGS)                 \
        $(LIBGNOMEUI_CFLAGS)                    \
        -I$(srcdir)/tray                        \
        -DLOCALEDIR=\"$(datadir)/locale\" \
+       -DGNOME_SHELL_LIBEXECDIR=\"$(libexecdir)\"      \
        -DGNOME_SHELL_DATADIR=\"$(pkgdatadir)\" \
        -DGNOME_SHELL_PKGLIBDIR=\"$(pkglibdir)\" \
        -DJSDIR=\"$(pkgdatadir)/js\"
@@ -88,8 +89,6 @@ libgnome_shell_la_SOURCES =           \
        shell-arrow.c                   \
        shell-doc-system.c              \
        shell-embedded-window.c         \
-       shell-evolution-event-source.h  \
-       shell-evolution-event-source.c  \
        shell-generic-container.c       \
        shell-gtk-embed.c               \
        shell-global.c                  \
@@ -216,10 +215,9 @@ libgnome_shell_la_LIBADD = \
        libgdmuser-1.0.la       \
        libtray.la              \
        libgvc.la               \
-       libcalendar-client.la   \
        $(NULL)
 
-libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
+libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags) $(LIBECAL_CFLAGS)
 
 typelibdir = $(pkglibdir)
 typelib_DATA = Shell-0.1.typelib St-1.0.typelib Gdm-1.0.typelib Gvc-1.0.typelib
diff --git a/src/calendar-client/README b/src/calendar-client/README
deleted file mode 100644 (file)
index ad9b5e3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Please keep in sync with gnome-panel.
diff --git a/src/calendar-client/calendar-client.c b/src/calendar-client/calendar-client.c
deleted file mode 100644 (file)
index bbdb473..0000000
+++ /dev/null
@@ -1,2169 +0,0 @@
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- *     Mark McLoughlin  <mark@skynet.ie>
- *     William Jon McCann  <mccann@jhu.edu>
- *     Martin Grimme  <martin@pycage.de>
- *     Christian Kellner  <gicmo@xatom.net>
- */
-
-#include <config.h>
-
-#include "calendar-client.h"
-
-#include <libintl.h>
-#include <string.h>
-#define HANDLE_LIBICAL_MEMORY
-#include <libecal/e-cal.h>
-#include <libecal/e-cal-time-util.h>
-#include <libecal/e-cal-recur.h>
-
-#include "calendar-sources.h"
-
-#undef CALENDAR_ENABLE_DEBUG
-#include "calendar-debug.h"
-
-#define CALENDAR_CONFIG_PREFIX   "/apps/evolution/calendar"
-#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
-
-#ifndef _
-#define _(x) gettext(x)
-#endif
-
-#ifndef N_
-#define N_(x) x
-#endif
-
-#define CALENDAR_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_CLIENT, CalendarClientPrivate))
-
-typedef struct _CalendarClientQuery  CalendarClientQuery;
-typedef struct _CalendarClientSource CalendarClientSource;
-
-struct _CalendarClientQuery
-{
-  ECalView   *view;
-  GHashTable *events;
-};
-
-struct _CalendarClientSource
-{
-  CalendarClient      *client;
-  ECal                *source;
-
-  CalendarClientQuery  completed_query;
-  CalendarClientQuery  in_progress_query;
-
-  guint                changed_signal_id;
-
-  guint                query_completed : 1;
-  guint                query_in_progress : 1;
-};
-
-struct _CalendarClientPrivate
-{
-  CalendarSources     *calendar_sources;
-
-  GSList              *appointment_sources;
-  GSList              *task_sources;
-
-  icaltimezone        *zone;
-
-  guint                zone_listener;
-  GConfClient         *gconf_client;
-
-  guint                day;
-  guint                month;
-  guint                year;
-};
-
-static void calendar_client_class_init   (CalendarClientClass *klass);
-static void calendar_client_init         (CalendarClient      *client);
-static void calendar_client_finalize     (GObject             *object);
-static void calendar_client_set_property (GObject             *object,
-                                         guint                prop_id,
-                                         const GValue        *value,
-                                         GParamSpec          *pspec);
-static void calendar_client_get_property (GObject             *object,
-                                         guint                prop_id,
-                                         GValue              *value,
-                                         GParamSpec          *pspec);
-
-static GSList *calendar_client_update_sources_list         (CalendarClient       *client,
-                                                           GSList               *sources,
-                                                           GSList               *esources,
-                                                           guint                 changed_signal_id);
-static void    calendar_client_appointment_sources_changed (CalendarClient       *client);
-static void    calendar_client_task_sources_changed        (CalendarClient       *client);
-
-static void calendar_client_stop_query  (CalendarClient       *client,
-                                        CalendarClientSource *source,
-                                        CalendarClientQuery  *query);
-static void calendar_client_start_query (CalendarClient       *client,
-                                        CalendarClientSource *source,
-                                        const char           *query);
-
-static void calendar_client_source_finalize (CalendarClientSource *source);
-static void calendar_client_query_finalize  (CalendarClientQuery  *query);
-
-static void
-calendar_client_update_appointments (CalendarClient *client);
-static void
-calendar_client_update_tasks (CalendarClient *client);
-
-enum
-{
-  PROP_O,
-  PROP_DAY,
-  PROP_MONTH,
-  PROP_YEAR
-};
-
-enum
-{
-  APPOINTMENTS_CHANGED,
-  TASKS_CHANGED,
-  LAST_SIGNAL
-};
-
-static GObjectClass *parent_class = NULL;
-static guint         signals [LAST_SIGNAL] = { 0, };
-
-GType
-calendar_client_get_type (void)
-{
-  static GType client_type = 0;
-  
-  if (!client_type)
-    {
-      static const GTypeInfo client_info =
-      {
-       sizeof (CalendarClientClass),
-       NULL,           /* base_init */
-       NULL,           /* base_finalize */
-       (GClassInitFunc) calendar_client_class_init,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-       sizeof (CalendarClient),
-       0,              /* n_preallocs */
-       (GInstanceInitFunc) calendar_client_init,
-      };
-      
-      client_type = g_type_register_static (G_TYPE_OBJECT,
-                                           "CalendarClient",
-                                           &client_info, 0);
-    }
-  
-  return client_type;
-}
-
-static void
-calendar_client_class_init (CalendarClientClass *klass)
-{
-  GObjectClass *gobject_class = (GObjectClass *) klass;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class->finalize     = calendar_client_finalize;
-  gobject_class->set_property = calendar_client_set_property;
-  gobject_class->get_property = calendar_client_get_property;
-
-  g_type_class_add_private (klass, sizeof (CalendarClientPrivate));
-
-  g_object_class_install_property (gobject_class,
-                                  PROP_DAY,
-                                  g_param_spec_uint ("day",
-                                                     "Day",
-                                                     "The currently monitored day between 1 and 31 (0 denotes unset)",
-                                                     0, G_MAXUINT, 0,
-                                                     G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                  PROP_MONTH,
-                                  g_param_spec_uint ("month",
-                                                     "Month",
-                                                     "The currently monitored month between 0 and 11",
-                                                     0, G_MAXUINT, 0,
-                                                     G_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                  PROP_YEAR,
-                                  g_param_spec_uint ("year",
-                                                     "Year",
-                                                     "The currently monitored year",
-                                                     0, G_MAXUINT, 0,
-                                                     G_PARAM_READWRITE));
-
-  signals [APPOINTMENTS_CHANGED] =
-    g_signal_new ("appointments-changed",
-                 G_TYPE_FROM_CLASS (gobject_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
-                 NULL,
-                 NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
-
-  signals [TASKS_CHANGED] =
-    g_signal_new ("tasks-changed",
-                 G_TYPE_FROM_CLASS (gobject_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (CalendarClientClass, tasks_changed),
-                 NULL,
-                 NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
-}
-
-/* Timezone code adapted from evolution/calendar/gui/calendar-config.c */
-/* The current timezone, e.g. "Europe/London". It may be NULL, in which case
-   you should assume UTC. */
-static gchar *
-calendar_client_config_get_timezone (GConfClient *gconf_client)
-{
-  char *location;
-
-  location = gconf_client_get_string (gconf_client,
-                                      CALENDAR_CONFIG_TIMEZONE,
-                                      NULL);
-
-  return location;
-}
-
-static icaltimezone *
-calendar_client_config_get_icaltimezone (GConfClient *gconf_client)
-{
-  char         *location;
-  icaltimezone *zone = NULL;
-       
-  location = calendar_client_config_get_timezone (gconf_client);
-  if (!location)
-    return icaltimezone_get_utc_timezone ();
-
-  zone = icaltimezone_get_builtin_timezone (location);
-  g_free (location);
-       
-  return zone;
-}
-
-static void
-calendar_client_set_timezone (CalendarClient *client) 
-{
-  GSList *l;
-  GSList *esources;
-
-  client->priv->zone = calendar_client_config_get_icaltimezone (client->priv->gconf_client);
-
-  esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
-  for (l = esources; l; l = l->next) {
-    ECal *source = l->data;
-                       
-    e_cal_set_default_timezone (source, client->priv->zone, NULL);
-  }
-}
-
-static void
-calendar_client_timezone_changed_cb (GConfClient    *gconf_client,
-                                     guint           id,
-                                     GConfEntry     *entry,
-                                     CalendarClient *client)
-{
-  calendar_client_set_timezone (client);
-}
-
-static void
-cal_opened_cb (ECal                 *ecal,
-               ECalendarStatus       status,
-               CalendarClientSource *cl_source)
-{
-  ECalSourceType  s_type;
-  CalendarClient *client = cl_source->client;
-
-  s_type = e_cal_get_source_type (ecal);
-
-  if (status == E_CALENDAR_STATUS_BUSY &&
-      e_cal_get_load_state (ecal) == E_CAL_LOAD_NOT_LOADED)
-    {
-      e_cal_open_async (ecal, FALSE);
-      return;
-    }
-  
-  g_signal_handlers_disconnect_by_func (ecal, cal_opened_cb, cl_source);
-
-  if (status != E_CALENDAR_STATUS_OK)
-    {
-      if (s_type == E_CAL_SOURCE_TYPE_EVENT)
-        client->priv->appointment_sources = g_slist_remove (client->priv->appointment_sources,
-                                                            cl_source);
-      else
-        client->priv->task_sources = g_slist_remove (client->priv->task_sources,
-                                                     cl_source);
-
-      calendar_client_source_finalize (cl_source);
-      g_free (cl_source);
-
-      return;
-    }
-
-  if (s_type == E_CAL_SOURCE_TYPE_EVENT)
-    calendar_client_update_appointments (client);
-  else
-    calendar_client_update_tasks (client);
-}
-
-static void
-load_calendars (CalendarClient    *client,
-                CalendarEventType  type) 
-{
-  GSList *l, *clients;
-
-  switch (type)
-    {
-      case CALENDAR_EVENT_APPOINTMENT:
-        clients = client->priv->appointment_sources;
-        break;
-      case CALENDAR_EVENT_TASK:
-        clients = client->priv->task_sources;
-        break;
-      default:
-        g_assert_not_reached ();
-    }
-
-  for (l = clients; l != NULL; l = l->next)
-    {
-      ECal *ecal;      
-      CalendarClientSource *cl_source = l->data;
-
-      ecal = cl_source->source;
-
-      if (e_cal_get_load_state (ecal) == E_CAL_LOAD_LOADED)
-        continue;
-
-      g_signal_connect (G_OBJECT (ecal), "cal_opened",
-                        G_CALLBACK (cal_opened_cb), cl_source);
-      e_cal_open_async (ecal, TRUE);
-    }
-}
-
-static void
-calendar_client_init (CalendarClient *client)
-{
-  GSList *esources;
-
-  client->priv = CALENDAR_CLIENT_GET_PRIVATE (client);
-
-  client->priv->calendar_sources = calendar_sources_get ();
-  client->priv->gconf_client = gconf_client_get_default ();
-
-  esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
-  client->priv->appointment_sources =
-    calendar_client_update_sources_list (client, NULL, esources, signals [APPOINTMENTS_CHANGED]);
-
-  esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
-  client->priv->task_sources =
-    calendar_client_update_sources_list (client, NULL, esources, signals [TASKS_CHANGED]);
- 
-  /* set the timezone before loading the clients */ 
-  calendar_client_set_timezone (client);
-  load_calendars (client, CALENDAR_EVENT_APPOINTMENT);
-  load_calendars (client, CALENDAR_EVENT_TASK);
-
-  g_signal_connect_swapped (client->priv->calendar_sources,
-                           "appointment-sources-changed",
-                           G_CALLBACK (calendar_client_appointment_sources_changed),
-                           client);
-  g_signal_connect_swapped (client->priv->calendar_sources,
-                           "task-sources-changed",
-                           G_CALLBACK (calendar_client_task_sources_changed),
-                           client);
-
-  gconf_client_add_dir (client->priv->gconf_client,
-                       CALENDAR_CONFIG_PREFIX,
-                       GCONF_CLIENT_PRELOAD_NONE,
-                       NULL);
-
-  client->priv->zone_listener = gconf_client_notify_add (client->priv->gconf_client,
-                                                         CALENDAR_CONFIG_TIMEZONE,
-                                                         (GConfClientNotifyFunc) calendar_client_timezone_changed_cb,
-                                                         client, NULL, NULL);
-
-  client->priv->day   = -1;
-  client->priv->month = -1;
-  client->priv->year  = -1;
-}
-
-static void
-calendar_client_finalize (GObject *object)
-{
-  CalendarClient *client = CALENDAR_CLIENT (object);
-  GSList         *l;
-
-  if (client->priv->zone_listener)
-    {
-      gconf_client_notify_remove (client->priv->gconf_client,
-                                  client->priv->zone_listener);
-      client->priv->zone_listener = 0;
-    }
-
-  gconf_client_remove_dir (client->priv->gconf_client,
-                           CALENDAR_CONFIG_PREFIX,
-                           NULL);
-
-  if (client->priv->gconf_client)
-    g_object_unref (client->priv->gconf_client);
-  client->priv->gconf_client = NULL;
-
-  for (l = client->priv->appointment_sources; l; l = l->next)
-    {
-      calendar_client_source_finalize (l->data);
-      g_free (l->data);
-    }
-  g_slist_free (client->priv->appointment_sources);
-  client->priv->appointment_sources = NULL;
-
-  for (l = client->priv->task_sources; l; l = l->next)
-    {
-      calendar_client_source_finalize (l->data);
-      g_free (l->data);
-    }
-  g_slist_free (client->priv->task_sources);
-  client->priv->task_sources = NULL;
-
-  if (client->priv->calendar_sources)
-    g_object_unref (client->priv->calendar_sources);
-  client->priv->calendar_sources = NULL;
-
-  if (G_OBJECT_CLASS (parent_class)->finalize)
-    G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-calendar_client_set_property (GObject      *object,
-                             guint         prop_id,
-                             const GValue *value,
-                             GParamSpec   *pspec)
-{
-  CalendarClient *client = CALENDAR_CLIENT (object);
-
-  switch (prop_id)
-    {
-    case PROP_DAY:
-      calendar_client_select_day (client, g_value_get_uint (value));
-      break;
-    case PROP_MONTH:
-      calendar_client_select_month (client,
-                                   g_value_get_uint (value),
-                                   client->priv->year);
-      break;
-    case PROP_YEAR:
-      calendar_client_select_month (client,
-                                   client->priv->month,
-                                   g_value_get_uint (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-calendar_client_get_property (GObject    *object,
-                             guint       prop_id,
-                             GValue     *value,
-                             GParamSpec *pspec)
-{
-  CalendarClient *client = CALENDAR_CLIENT (object);
-
-  switch (prop_id)
-    {
-    case PROP_DAY:
-      g_value_set_uint (value, client->priv->day);
-      break;
-    case PROP_MONTH:
-      g_value_set_uint (value, client->priv->month);
-      break;
-    case PROP_YEAR:
-      g_value_set_uint (value, client->priv->year);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-CalendarClient *
-calendar_client_new (void)
-{
-  return g_object_new (CALENDAR_TYPE_CLIENT, NULL);
-}
-
-/* @day and @month can happily be out of range as
- * mktime() will normalize them correctly. From mktime(3):
- *
- * "If structure members are outside their legal interval,
- *  they will be normalized (so that, e.g., 40 October is
- *  changed into 9 November)."
- *
- * "What?", you say, "Something useful in libc?"
- */
-static inline time_t
-make_time_for_day_begin (int day,
-                        int month,
-                        int year)
-{
-  struct tm localtime_tm = { 0, };
-
-  localtime_tm.tm_mday  = day;
-  localtime_tm.tm_mon   = month;
-  localtime_tm.tm_year  = year - 1900;
-  localtime_tm.tm_isdst = -1;
-
-  return mktime (&localtime_tm);
-}
-
-static inline char *
-make_isodate_for_day_begin (int day,
-                           int month,
-                           int year)
-{
-  time_t utctime;
-
-  utctime = make_time_for_day_begin (day, month, year);
-
-  return utctime != -1 ? isodate_from_time_t (utctime) : NULL;
-}
-
-static time_t
-get_time_from_property (icalcomponent         *ical,
-                       icalproperty_kind      prop_kind,
-                       struct icaltimetype (* get_prop_func) (const icalproperty *prop),
-                        icaltimezone          *default_zone)
-{
-  icalproperty        *prop;
-  struct icaltimetype  ical_time;
-  icalparameter       *param;
-  icaltimezone        *timezone = NULL;
-  
-  prop = icalcomponent_get_first_property (ical, prop_kind);
-  if (!prop)
-    return 0;
-
-  ical_time = get_prop_func (prop);
-
-  param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
-  if (param)
-    timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param));
-  else if (icaltime_is_utc (ical_time))
-    timezone = icaltimezone_get_utc_timezone ();
-  else 
-    timezone = default_zone;
-
-  return icaltime_as_timet_with_zone (ical_time, timezone);
-}
-
-static char *
-get_ical_uid (icalcomponent *ical)
-{
-  return g_strdup (icalcomponent_get_uid (ical));
-}
-
-static char *
-get_ical_rid (icalcomponent *ical)
-{
-  icalproperty        *prop;
-  struct icaltimetype  ical_time;
-  
-  prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY);
-  if (!prop)
-    return NULL;
-
-  ical_time = icalproperty_get_recurrenceid (prop);
-
-  return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ? 
-    g_strdup (icaltime_as_ical_string (ical_time)) : NULL;
-}
-
-static char *
-get_ical_summary (icalcomponent *ical)
-{
-  icalproperty *prop;
-
-  prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY);
-  if (!prop)
-    return NULL;
-
-  return g_strdup (icalproperty_get_summary (prop));
-}
-
-static char *
-get_ical_description (icalcomponent *ical)
-{
-  icalproperty *prop;
-
-  prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY);
-  if (!prop)
-    return NULL;
-
-  return g_strdup (icalproperty_get_description (prop));
-}
-
-static inline time_t
-get_ical_start_time (icalcomponent *ical,
-                     icaltimezone  *default_zone)
-{
-  return get_time_from_property (ical,
-                                ICAL_DTSTART_PROPERTY,
-                                icalproperty_get_dtstart,
-                                 default_zone);
-}
-
-static inline time_t
-get_ical_end_time (icalcomponent *ical,
-                   icaltimezone  *default_zone)
-{
-  return get_time_from_property (ical,
-                                ICAL_DTEND_PROPERTY,
-                                icalproperty_get_dtend,
-                                 default_zone);
-}
-
-static gboolean
-get_ical_is_all_day (icalcomponent *ical,
-                     time_t         start_time,
-                     icaltimezone  *default_zone)
-{
-  icalproperty            *prop;
-  struct tm               *start_tm;
-  time_t                   end_time;
-  struct icaldurationtype  duration;
-  struct icaltimetype      start_icaltime;
-
-  start_icaltime = icalcomponent_get_dtstart (ical);
-  if (start_icaltime.is_date)
-    return TRUE;
-
-  start_tm = gmtime (&start_time);
-  if (start_tm->tm_sec  != 0 ||
-      start_tm->tm_min  != 0 ||
-      start_tm->tm_hour != 0)
-    return FALSE;
-
-  if ((end_time = get_ical_end_time (ical, default_zone)))
-    return (end_time - start_time) % 86400 == 0;
-
-  prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY);
-  if (!prop)
-    return FALSE;
-
-  duration = icalproperty_get_duration (prop);
-
-  return icaldurationtype_as_int (duration) % 86400 == 0;
-}
-
-static inline time_t
-get_ical_due_time (icalcomponent *ical,
-                   icaltimezone  *default_zone)
-{
-  return get_time_from_property (ical,
-                                ICAL_DUE_PROPERTY,
-                                icalproperty_get_due,
-                                 default_zone);
-}
-
-static guint
-get_ical_percent_complete (icalcomponent *ical)
-{
-  icalproperty *prop;
-  icalproperty_status status;
-  int           percent_complete;
-
-  status = icalcomponent_get_status (ical);
-  if (status == ICAL_STATUS_COMPLETED)
-    return 100;
-
-  prop = icalcomponent_get_first_property (ical, ICAL_COMPLETED_PROPERTY);
-  if (prop)
-    return 100;
-
-  prop = icalcomponent_get_first_property (ical, ICAL_PERCENTCOMPLETE_PROPERTY);
-  if (!prop)
-    return 0;
-
-  percent_complete = icalproperty_get_percentcomplete (prop);
-
-  return CLAMP (percent_complete, 0, 100);
-}
-
-static inline time_t
-get_ical_completed_time (icalcomponent *ical,
-                         icaltimezone  *default_zone)
-{
-  return get_time_from_property (ical,
-                                ICAL_COMPLETED_PROPERTY,
-                                icalproperty_get_completed,
-                                 default_zone);
-}
-
-static int
-get_ical_priority (icalcomponent *ical)
-{
-  icalproperty *prop;
-
-  prop = icalcomponent_get_first_property (ical, ICAL_PRIORITY_PROPERTY);
-  if (!prop)
-    return -1;
-
-  return icalproperty_get_priority (prop);
-}
-
-static char *
-get_source_color (ECal *esource)
-{
-  ESource *source;
-
-  g_return_val_if_fail (E_IS_CAL (esource), NULL);
-
-  source = e_cal_get_source (esource);
-
-  return g_strdup (e_source_peek_color_spec (source));
-}
-
-static gchar *
-get_source_uri (ECal *esource)
-{
-    ESource *source;
-    gchar   *string;
-    gchar  **list;
-
-    g_return_val_if_fail (E_IS_CAL (esource), NULL);
-
-    source = e_cal_get_source (esource);
-    string = g_strdup (e_source_get_uri (source));
-    if (string) {
-        list = g_strsplit (string, ":", 2);
-        g_free (string);
-
-        if (list[0]) {
-            string = g_strdup (list[0]);
-            g_strfreev (list);
-            return string;
-        }
-       g_strfreev (list);
-    }
-    return NULL;
-}
-
-static inline int
-null_safe_strcmp (const char *a,
-                 const char *b)
-{
-  return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b);
-}
-
-static inline gboolean
-calendar_appointment_equal (CalendarAppointment *a,
-                           CalendarAppointment *b)
-{
-  GSList *la, *lb;
-
-  if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences))
-      return FALSE;
-
-  for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next)
-    {
-      CalendarOccurrence *oa = la->data;
-      CalendarOccurrence *ob = lb->data;
-
-      if (oa->start_time != ob->start_time ||
-         oa->end_time   != ob->end_time)
-       return FALSE;
-    }
-
-  return
-    null_safe_strcmp (a->uid,          b->uid)          == 0 &&
-    null_safe_strcmp (a->uri,          b->uri)          == 0 &&
-    null_safe_strcmp (a->summary,      b->summary)      == 0 &&
-    null_safe_strcmp (a->description,  b->description)  == 0 &&
-    null_safe_strcmp (a->color_string, b->color_string) == 0 &&
-    a->start_time == b->start_time                         &&
-    a->end_time   == b->end_time                           &&
-    a->is_all_day == b->is_all_day;
-}
-
-static void
-calendar_appointment_copy (CalendarAppointment *appointment,
-                          CalendarAppointment *appointment_copy)
-{
-  GSList *l;
-
-  g_assert (appointment != NULL);
-  g_assert (appointment_copy != NULL);
-
-  appointment_copy->occurrences = g_slist_copy (appointment->occurrences);
-  for (l = appointment_copy->occurrences; l; l = l->next)
-    {
-      CalendarOccurrence *occurrence = l->data;
-      CalendarOccurrence *occurrence_copy;
-
-      occurrence_copy             = g_new0 (CalendarOccurrence, 1);
-      occurrence_copy->start_time = occurrence->start_time;
-      occurrence_copy->end_time   = occurrence->end_time;
-
-      l->data = occurrence_copy;
-    }
-
-  appointment_copy->uid          = g_strdup (appointment->uid);
-  appointment_copy->uri          = g_strdup (appointment->uri);
-  appointment_copy->summary      = g_strdup (appointment->summary);
-  appointment_copy->description  = g_strdup (appointment->description);
-  appointment_copy->color_string = g_strdup (appointment->color_string);
-  appointment_copy->start_time   = appointment->start_time;
-  appointment_copy->end_time     = appointment->end_time;
-  appointment_copy->is_all_day   = appointment->is_all_day;
-}
-
-static void
-calendar_appointment_finalize (CalendarAppointment *appointment)
-{
-  GSList *l;
-
-  for (l = appointment->occurrences; l; l = l->next)
-    g_free (l->data);
-  g_slist_free (appointment->occurrences);
-  appointment->occurrences = NULL;
-
-  g_free (appointment->uid);
-  appointment->uid = NULL;
-
-  g_free (appointment->rid);
-  appointment->rid = NULL;
-
-  g_free (appointment->uri);
-  appointment->uri = NULL;
-
-  g_free (appointment->summary);
-  appointment->summary = NULL;
-
-  g_free (appointment->description);
-  appointment->description = NULL;
-
-  g_free (appointment->color_string);
-  appointment->color_string = NULL;
-
-  appointment->start_time = 0;
-  appointment->is_all_day = FALSE;
-}
-
-static void
-calendar_appointment_init (CalendarAppointment  *appointment,
-                          icalcomponent        *ical,
-                           CalendarClientSource *source,
-                           icaltimezone         *default_zone)
-{
-  appointment->uid          = get_ical_uid (ical);
-  appointment->rid          = get_ical_rid (ical);
-  appointment->uri          = get_source_uri (source->source);
-  appointment->summary      = get_ical_summary (ical);
-  appointment->description  = get_ical_description (ical);
-  appointment->color_string = get_source_color (source->source);
-  appointment->start_time   = get_ical_start_time (ical, default_zone);
-  appointment->end_time     = get_ical_end_time (ical, default_zone);
-  appointment->is_all_day   = get_ical_is_all_day (ical,
-                                                   appointment->start_time,
-                                                   default_zone);
-}
-
-static icaltimezone *
-resolve_timezone_id (const char *tzid,
-                    ECal       *source)
-{
-  icaltimezone *retval;
-
-  retval = icaltimezone_get_builtin_timezone_from_tzid (tzid);
-  if (!retval)
-    {
-      e_cal_get_timezone (source, tzid, &retval, NULL);
-    }
-
-  return retval;
-}
-
-static gboolean
-calendar_appointment_collect_occurrence (ECalComponent  *component,
-                                        time_t          occurrence_start,
-                                        time_t          occurrence_end,
-                                        gpointer        data)
-{
-  CalendarOccurrence *occurrence;
-  GSList **collect_loc = data;
-
-  occurrence             = g_new0 (CalendarOccurrence, 1);
-  occurrence->start_time = occurrence_start;
-  occurrence->end_time   = occurrence_end;
-
-  *collect_loc = g_slist_prepend (*collect_loc, occurrence);
-
-  return TRUE;
-}
-
-static void
-calendar_appointment_generate_ocurrences (CalendarAppointment *appointment,
-                                         icalcomponent       *ical,
-                                         ECal                *source,
-                                         time_t               start,
-                                         time_t               end,
-                                          icaltimezone        *default_zone)
-{
-  ECalComponent *ecal;
-
-  g_assert (appointment->occurrences == NULL);
-
-  ecal = e_cal_component_new ();
-  e_cal_component_set_icalcomponent (ecal,
-                                    icalcomponent_new_clone (ical));
-
-  e_cal_recur_generate_instances (ecal,
-                                 start,
-                                 end,
-                                 calendar_appointment_collect_occurrence,
-                                 &appointment->occurrences,
-                                 (ECalRecurResolveTimezoneFn) resolve_timezone_id,
-                                 source,
-                                 default_zone);
-
-  g_object_unref (ecal);
-
-  appointment->occurrences = g_slist_reverse (appointment->occurrences);
-}
-
-static inline gboolean
-calendar_task_equal (CalendarTask *a,
-                    CalendarTask *b)
-{
-  return
-    null_safe_strcmp (a->uid,          b->uid)          == 0 &&
-    null_safe_strcmp (a->summary,      b->summary)      == 0 &&
-    null_safe_strcmp (a->description,  b->description)  == 0 &&
-    null_safe_strcmp (a->color_string, b->color_string) == 0 &&
-    a->start_time       == b->start_time                   &&
-    a->due_time         == b->due_time                     &&
-    a->percent_complete == b->percent_complete             &&
-    a->completed_time   == b->completed_time               &&
-    a->priority         == b->priority;
-}
-
-static void
-calendar_task_copy (CalendarTask *task,
-                   CalendarTask *task_copy)
-{
-  g_assert (task != NULL);
-  g_assert (task_copy != NULL);
-
-  task_copy->uid              = g_strdup (task->uid);
-  task_copy->summary          = g_strdup (task->summary);
-  task_copy->description      = g_strdup (task->description);
-  task_copy->color_string     = g_strdup (task->color_string);
-  task_copy->start_time       = task->start_time;
-  task_copy->due_time         = task->due_time;
-  task_copy->percent_complete = task->percent_complete;
-  task_copy->completed_time   = task->completed_time;
-  task_copy->priority         = task->priority;
-}
-
-static void
-calendar_task_finalize (CalendarTask *task)
-{
-  g_free (task->uid);
-  task->uid = NULL;
-
-  g_free (task->summary);
-  task->summary = NULL;
-
-  g_free (task->description);
-  task->description = NULL;
-
-  g_free (task->color_string);
-  task->color_string = NULL;
-
-  task->percent_complete = 0;
-}
-
-static void
-calendar_task_init (CalendarTask         *task,
-                   icalcomponent        *ical,
-                    CalendarClientSource *source,
-                    icaltimezone         *default_zone)
-{
-  task->uid              = get_ical_uid (ical);
-  task->summary          = get_ical_summary (ical);
-  task->description      = get_ical_description (ical);
-  task->color_string     = get_source_color (source->source);
-  task->start_time       = get_ical_start_time (ical, default_zone);
-  task->due_time         = get_ical_due_time (ical, default_zone);
-  task->percent_complete = get_ical_percent_complete (ical);
-  task->completed_time   = get_ical_completed_time (ical, default_zone);
-  task->priority         = get_ical_priority (ical);
-}
-
-void
-calendar_event_free (CalendarEvent *event)
-{
-  switch (event->type)
-    {
-    case CALENDAR_EVENT_APPOINTMENT:
-      calendar_appointment_finalize (CALENDAR_APPOINTMENT (event));
-      break;
-    case CALENDAR_EVENT_TASK:
-      calendar_task_finalize (CALENDAR_TASK (event));
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-
-  g_free (event);
-}
-
-static CalendarEvent *
-calendar_event_new (icalcomponent        *ical,
-                    CalendarClientSource *source,
-                    icaltimezone         *default_zone)
-{
-  CalendarEvent *event;
-
-  event = g_new0 (CalendarEvent, 1);
-
-  switch (icalcomponent_isa (ical))
-    {
-    case ICAL_VEVENT_COMPONENT:
-      event->type = CALENDAR_EVENT_APPOINTMENT;
-      calendar_appointment_init (CALENDAR_APPOINTMENT (event),
-                                 ical,
-                                 source,
-                                 default_zone);
-      break;
-    case ICAL_VTODO_COMPONENT:
-      event->type = CALENDAR_EVENT_TASK;
-      calendar_task_init (CALENDAR_TASK (event),
-                          ical,
-                          source,
-                          default_zone);
-      break;
-    default:
-      g_warning ("Unknown calendar component type: %d\n",
-                 icalcomponent_isa (ical));
-      g_free (event);
-      return NULL;
-    }
-
-  return event;
-}
-
-static CalendarEvent *
-calendar_event_copy (CalendarEvent *event)
-{
-  CalendarEvent *retval;
-
-  if (!event)
-    return NULL;
-
-  retval = g_new0 (CalendarEvent, 1);
-
-  retval->type = event->type;
-
-  switch (event->type)
-    {
-    case CALENDAR_EVENT_APPOINTMENT:
-      calendar_appointment_copy (CALENDAR_APPOINTMENT (event),
-                                CALENDAR_APPOINTMENT (retval));
-      break;
-    case CALENDAR_EVENT_TASK:
-      calendar_task_copy (CALENDAR_TASK (event),
-                         CALENDAR_TASK (retval));
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-
-  return retval;
-}
-
-static char *
-calendar_event_get_uid (CalendarEvent *event)
-{
-  switch (event->type)
-    {
-    case CALENDAR_EVENT_APPOINTMENT:
-      return g_strdup_printf ("%s%s", CALENDAR_APPOINTMENT (event)->uid, CALENDAR_APPOINTMENT (event)->rid ? CALENDAR_APPOINTMENT (event)->rid : ""); 
-      break;
-    case CALENDAR_EVENT_TASK:
-      return g_strdup (CALENDAR_TASK (event)->uid);
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-
-  return NULL;
-}
-
-static gboolean
-calendar_event_equal (CalendarEvent *a,
-                     CalendarEvent *b)
-{
-  if (!a && !b)
-    return TRUE;
-
-  if ((a && !b) || (!a && b))
-    return FALSE;
-
-  if (a->type != b->type)
-    return FALSE;
-
-  switch (a->type)
-    {
-    case CALENDAR_EVENT_APPOINTMENT:
-      return calendar_appointment_equal (CALENDAR_APPOINTMENT (a),
-                                        CALENDAR_APPOINTMENT (b));
-    case CALENDAR_EVENT_TASK:
-      return calendar_task_equal (CALENDAR_TASK (a),
-                                 CALENDAR_TASK (b));
-    default:
-      break;
-    }
- 
-  g_assert_not_reached ();
-
-  return FALSE;
-}
-
-static void
-calendar_event_generate_ocurrences (CalendarEvent *event,
-                                   icalcomponent *ical,
-                                   ECal          *source,
-                                   time_t         start,
-                                   time_t         end,
-                                    icaltimezone  *default_zone)
-{
-  if (event->type != CALENDAR_EVENT_APPOINTMENT)
-    return;
-
-  calendar_appointment_generate_ocurrences (CALENDAR_APPOINTMENT (event),
-                                           ical,
-                                           source,
-                                           start,
-                                           end,
-                                            default_zone);
-}
-
-static inline void
-calendar_event_debug_dump (CalendarEvent *event)
-{
-#ifdef CALENDAR_ENABLE_DEBUG
-  switch (event->type)
-    {
-    case CALENDAR_EVENT_APPOINTMENT:
-      {
-       char   *start_str;
-       char   *end_str;
-       GSList *l;
-
-       start_str = CALENDAR_APPOINTMENT (event)->start_time ?
-                           isodate_from_time_t (CALENDAR_APPOINTMENT (event)->start_time) :
-                           g_strdup ("(undefined)");
-       end_str = CALENDAR_APPOINTMENT (event)->end_time ?
-                           isodate_from_time_t (CALENDAR_APPOINTMENT (event)->end_time) :
-                           g_strdup ("(undefined)");
-         
-       dprintf ("Appointment: uid '%s', summary '%s', description '%s', "
-                "start_time '%s', end_time '%s', is_all_day %s\n",
-                CALENDAR_APPOINTMENT (event)->uid,
-                CALENDAR_APPOINTMENT (event)->summary,
-                CALENDAR_APPOINTMENT (event)->description,
-                start_str,
-                end_str,
-                CALENDAR_APPOINTMENT (event)->is_all_day ? "(true)" : "(false)");
-
-       g_free (start_str);
-       g_free (end_str);
-
-       dprintf ("  Occurrences:\n");
-       for (l = CALENDAR_APPOINTMENT (event)->occurrences; l; l = l->next)
-         {
-           CalendarOccurrence *occurrence = l->data;
-
-           start_str = occurrence->start_time ?
-             isodate_from_time_t (occurrence->start_time) :
-             g_strdup ("(undefined)");
-           
-           end_str = occurrence->end_time ?
-             isodate_from_time_t (occurrence->end_time) :
-             g_strdup ("(undefined)");
-
-           dprintf ("    start_time '%s', end_time '%s'\n",
-                    start_str, end_str);
-
-           g_free (start_str);
-           g_free (end_str);
-         }
-      }
-      break;
-    case CALENDAR_EVENT_TASK:
-      {
-       char *start_str;
-       char *due_str;
-       char *completed_str;
-
-       start_str = CALENDAR_TASK (event)->start_time ?
-                           isodate_from_time_t (CALENDAR_TASK (event)->start_time) :
-                           g_strdup ("(undefined)");
-       due_str = CALENDAR_TASK (event)->due_time ?
-                           isodate_from_time_t (CALENDAR_TASK (event)->due_time) :
-                           g_strdup ("(undefined)");
-       completed_str = CALENDAR_TASK (event)->completed_time ?
-                           isodate_from_time_t (CALENDAR_TASK (event)->completed_time) :
-                           g_strdup ("(undefined)");
-
-       dprintf ("Task: uid '%s', summary '%s', description '%s', "
-                "start_time '%s', due_time '%s', percent_complete %d, completed_time '%s'\n",
-                CALENDAR_TASK (event)->uid,
-                CALENDAR_TASK (event)->summary,
-                CALENDAR_TASK (event)->description,
-                start_str,
-                due_str,
-                CALENDAR_TASK (event)->percent_complete,
-                completed_str);
-
-       g_free (completed_str);
-      }
-      break;
-    default:
-      g_assert_not_reached ();
-      break;
-    }
-#endif
-}
-
-static inline CalendarClientQuery *
-goddamn_this_is_crack (CalendarClientSource *source,
-                      ECalView             *view,
-                      gboolean             *emit_signal)
-{
-  g_assert (view != NULL);
-
-  if (source->completed_query.view == view)
-    {
-      if (emit_signal)
-       *emit_signal = TRUE;
-      return &source->completed_query;
-    }
-  else if (source->in_progress_query.view == view)
-    {
-      if (emit_signal)
-       *emit_signal = FALSE;
-      return &source->in_progress_query;
-    }
-
-  g_assert_not_reached ();
-
-  return NULL;
-}
-
-static void
-calendar_client_handle_query_completed (CalendarClientSource *source,
-                                       ECalendarStatus       status,
-                                       ECalView             *view)
-{
-  CalendarClientQuery *query;
-
-  query = goddamn_this_is_crack (source, view, NULL);
-  
-  dprintf ("Query %p completed: %s\n", query, e_cal_get_error_message (status));
-
-  if (status != E_CALENDAR_STATUS_OK)
-    {
-      g_warning ("Calendar query failed: %s\n",
-                e_cal_get_error_message (status));
-      calendar_client_stop_query (source->client, source, query);
-      return;
-    }
-
-  g_assert (source->query_in_progress != FALSE);
-  g_assert (query == &source->in_progress_query);
-
-  calendar_client_query_finalize (&source->completed_query);
-
-  source->completed_query = source->in_progress_query;
-  source->query_completed = TRUE;
-
-  source->query_in_progress        = FALSE;
-  source->in_progress_query.view   = NULL;
-  source->in_progress_query.events = NULL;
-
-  g_signal_emit (source->client, source->changed_signal_id, 0);
-}
-
-static void
-calendar_client_handle_query_result (CalendarClientSource *source,
-                                    GList                *objects,
-                                    ECalView             *view)
-{
-  CalendarClientQuery *query;
-  CalendarClient      *client;
-  gboolean             emit_signal;
-  gboolean             events_changed;
-  GList               *l;
-  time_t               month_begin;
-  time_t               month_end;
-
-  client = source->client;
-
-  query = goddamn_this_is_crack (source, view, &emit_signal);
-
-  dprintf ("Query %p result: %d objects:\n",
-          query, g_list_length (objects));
-
-  month_begin = make_time_for_day_begin (1,
-                                        client->priv->month,
-                                        client->priv->year);
-
-  month_end = make_time_for_day_begin (1,
-                                      client->priv->month + 1,
-                                      client->priv->year);
-
-  events_changed = FALSE;
-  for (l = objects; l; l = l->next)
-    {
-      CalendarEvent *event;
-      CalendarEvent *old_event;
-      icalcomponent *ical = l->data;
-      char          *uid;
-      
-      event = calendar_event_new (ical, source, client->priv->zone);
-      if (!event)
-             continue;
-
-      calendar_event_generate_ocurrences (event,
-                                         ical,
-                                         source->source,
-                                         month_begin,
-                                         month_end,
-                                          client->priv->zone);
-
-      uid = calendar_event_get_uid (event);
-      
-      old_event = g_hash_table_lookup (query->events, uid);
-
-      if (!calendar_event_equal (event, old_event))
-       {
-         dprintf ("Event %s: ", old_event ? "modified" : "added");
-
-         calendar_event_debug_dump (event);
-
-         g_hash_table_replace (query->events, uid, event);
-
-         events_changed = TRUE;
-       }
-      else
-       {
-         g_free (uid);
-       }               
-    }
-
-  if (emit_signal && events_changed)
-    {
-      g_signal_emit (source->client, source->changed_signal_id, 0);
-    }
-}
-
-static gboolean
-check_object_remove (gpointer key,
-                     gpointer value,
-                     gpointer data)
-{
-  char             *uid = data;
-  ssize_t           len;
-
-  len = strlen (uid);
-  
-  if (len <= strlen (key) && strncmp (uid, key, len) == 0)
-    {
-      dprintf ("Event removed: ");
-
-      calendar_event_debug_dump (value);
-
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static void
-calendar_client_handle_objects_removed (CalendarClientSource *source,
-                                       GList                *ids,
-                                       ECalView             *view)
-{
-  CalendarClientQuery *query;
-  gboolean             emit_signal;
-  gboolean             events_changed;
-  GList               *l;
-
-  query = goddamn_this_is_crack (source, view, &emit_signal);
-
-  events_changed = FALSE;
-  for (l = ids; l; l = l->next)
-    {
-      CalendarEvent   *event;
-      ECalComponentId *id = l->data;
-      char            *uid = g_strdup_printf ("%s%s", id->uid, id->rid ? id->rid : "");
-
-      if (!id->rid || !(*id->rid))
-       {
-         int size = g_hash_table_size (query->events);
-
-         g_hash_table_foreach_remove (query->events, check_object_remove, id->uid);
-
-               if (size != g_hash_table_size (query->events))
-                       events_changed = TRUE;          
-       }
-      else if ((event = g_hash_table_lookup (query->events, uid)))
-       {
-         dprintf ("Event removed: ");
-
-         calendar_event_debug_dump (event);
-
-         g_assert (g_hash_table_remove (query->events, uid));
-
-         events_changed = TRUE;
-       }
-      g_free (uid);
-    }
-
-  if (emit_signal && events_changed)
-    {
-      g_signal_emit (source->client, source->changed_signal_id, 0);
-    }
-}
-
-static void
-calendar_client_query_finalize (CalendarClientQuery *query)
-{
-  if (query->view)
-    g_object_unref (query->view);
-  query->view = NULL;
-
-  if (query->events)
-    g_hash_table_destroy (query->events);
-  query->events = NULL;
-}
-
-static void
-calendar_client_stop_query (CalendarClient       *client,
-                           CalendarClientSource *source,
-                           CalendarClientQuery  *query)
-{
-  if (query == &source->in_progress_query)
-    {
-      dprintf ("Stopping in progress query %p\n", query);
-
-      g_assert (source->query_in_progress != FALSE);
-
-      source->query_in_progress = FALSE;
-    }
-  else if (query == &source->completed_query)
-    {
-      dprintf ("Stopping completed query %p\n", query);
-
-      g_assert (source->query_completed != FALSE);
-
-      source->query_completed = FALSE;
-    }
-  else
-    g_assert_not_reached ();
-  
-  calendar_client_query_finalize (query);
-}
-
-static void
-calendar_client_start_query (CalendarClient       *client,
-                            CalendarClientSource *source,
-                            const char           *query)
-{
-  ECalView *view = NULL;
-  GError   *error = NULL;
-
-  if (!e_cal_get_query (source->source, query, &view, &error))
-    {
-      g_warning ("Error preparing the query: '%s': %s\n",
-                query, error->message);
-      g_error_free (error);
-      return;
-    }
-
-  g_assert (view != NULL);
-
-  if (source->query_in_progress)
-    calendar_client_stop_query (client, source, &source->in_progress_query);
-  
-  dprintf ("Starting query %p: '%s'\n", &source->in_progress_query, query);
-
-  source->query_in_progress        = TRUE;
-  source->in_progress_query.view   = view;
-  source->in_progress_query.events =
-    g_hash_table_new_full (g_str_hash,
-                          g_str_equal,
-                          g_free,
-                          (GDestroyNotify) calendar_event_free);
-
-  g_signal_connect_swapped (view, "objects-added",
-                           G_CALLBACK (calendar_client_handle_query_result),
-                           source);
-  g_signal_connect_swapped (view, "objects-modified",
-                           G_CALLBACK (calendar_client_handle_query_result),
-                           source);
-  g_signal_connect_swapped (view, "objects-removed",
-                           G_CALLBACK (calendar_client_handle_objects_removed),
-                           source);
-  g_signal_connect_swapped (view, "view-done",
-                           G_CALLBACK (calendar_client_handle_query_completed),
-                           source);
-
-  e_cal_view_start (view);
-}
-
-static void
-calendar_client_update_appointments (CalendarClient *client)
-{
-  GSList *l;
-  char   *query;
-  char   *month_begin;
-  char   *month_end;
-
-  if (client->priv->month == -1 ||
-      client->priv->year  == -1)
-    return;
-
-  month_begin = make_isodate_for_day_begin (1,
-                                           client->priv->month,
-                                           client->priv->year);
-
-  month_end = make_isodate_for_day_begin (1,
-                                         client->priv->month + 1,
-                                         client->priv->year);
-
-  query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") "
-                                               "(make-time \"%s\")",
-                          month_begin, month_end);
-
-  for (l = client->priv->appointment_sources; l; l = l->next)
-    {
-      CalendarClientSource *cs = l->data;
-                  
-      if (e_cal_get_load_state (cs->source) != E_CAL_LOAD_LOADED)  
-        continue;
-
-      calendar_client_start_query (client, cs, query);
-    }
-
-  g_free (month_begin);
-  g_free (month_end);
-  g_free (query);
-}
-
-/* FIXME:
- * perhaps we should use evo's "hide_completed_tasks" pref?
- */
-static void
-calendar_client_update_tasks (CalendarClient *client)
-{
-  GSList *l;
-  char   *query;
-
-#ifdef FIX_BROKEN_TASKS_QUERY
-  /* FIXME: this doesn't work for tasks without a start or
-   *        due date
-   *        Look at filter_task() to see the behaviour we
-   *        want.
-   */
-  
-  char   *day_begin;
-  char   *day_end;
-
-  if (client->priv->day   == -1 ||
-      client->priv->month == -1 ||
-      client->priv->year  == -1)
-    return;
-
-  day_begin = make_isodate_for_day_begin (client->priv->day,
-                                         client->priv->month,
-                                         client->priv->year);
-
-  day_end = make_isodate_for_day_begin (client->priv->day + 1,
-                                       client->priv->month,
-                                       client->priv->year);
-  if (!day_begin || !day_end)
-    {
-      g_warning ("Cannot run query with invalid date: %dd %dy %dm\n",
-                client->priv->day,
-                client->priv->month,
-                client->priv->year);
-      g_free (day_begin);
-      g_free (day_end);
-      return;
-    }
-  
-  query = g_strdup_printf ("(and (occur-in-time-range? (make-time \"%s\") "
-                                                      "(make-time \"%s\")) "
-                             "(or (not is-completed?) "
-                               "(and (is-completed?) "
-                                    "(not (completed-before? (make-time \"%s\"))))))",
-                          day_begin, day_end, day_begin);
-#else
-  query = g_strdup ("#t");
-#endif /* FIX_BROKEN_TASKS_QUERY */
-
-  for (l = client->priv->task_sources; l; l = l->next)
-    {
-      CalendarClientSource *cs = l->data;
-
-      if (e_cal_get_load_state (cs->source) != E_CAL_LOAD_LOADED)  
-        continue;
-
-      calendar_client_start_query (client, cs, query);
-    }
-
-#ifdef FIX_BROKEN_TASKS_QUERY
-  g_free (day_begin);
-  g_free (day_end);
-#endif
-  g_free (query);
-}
-
-static void
-calendar_client_source_finalize (CalendarClientSource *source)
-{
-  source->client = NULL;
-
-  if (source->source) {
-    g_signal_handlers_disconnect_by_func (source->source,
-                                          cal_opened_cb, source);
-    g_object_unref (source->source);
-  }
-  source->source = NULL;
-
-  calendar_client_query_finalize (&source->completed_query);
-  calendar_client_query_finalize (&source->in_progress_query);
-  
-  source->query_completed   = FALSE;
-  source->query_in_progress = FALSE;
-}
-
-static int
-compare_calendar_sources (CalendarClientSource *s1,
-                         CalendarClientSource *s2)
-{
-  return (s1->source == s2->source) ? 0 : 1;
-}
-
-static GSList *
-calendar_client_update_sources_list (CalendarClient *client,
-                                    GSList         *sources,
-                                    GSList         *esources,
-                                    guint           changed_signal_id)
-{
-  GSList *retval, *l;
-
-  retval = NULL;
-
-  for (l = esources; l; l = l->next)
-    {
-      CalendarClientSource  dummy_source;
-      CalendarClientSource *new_source;
-      GSList               *s;
-      ECal                 *esource = l->data;
-
-      dummy_source.source = esource;
-
-      dprintf ("update_sources_list: adding client %s: ",
-              e_source_peek_uid (e_cal_get_source (esource)));
-
-      if ((s = g_slist_find_custom (sources,
-                                   &dummy_source,
-                                   (GCompareFunc) compare_calendar_sources)))
-       {
-         dprintf ("already on list\n");
-         new_source = s->data;
-         sources = g_slist_delete_link (sources, s);
-       }
-      else
-       {
-         dprintf ("added\n");
-         new_source                    = g_new0 (CalendarClientSource, 1);
-         new_source->client            = client;
-         new_source->source            = g_object_ref (esource);
-         new_source->changed_signal_id = changed_signal_id;
-       }
-
-      retval = g_slist_prepend (retval, new_source);
-    }
-
-  for (l = sources; l; l = l->next)
-    {
-      CalendarClientSource *source = l->data;
-
-      dprintf ("Removing client %s from list\n",
-              e_source_peek_uid (e_cal_get_source (source->source)));
-
-      calendar_client_source_finalize (source);
-      g_free (source);
-    }
-  g_slist_free (sources);
-
-  return retval;
-}
-
-static void
-calendar_client_appointment_sources_changed (CalendarClient  *client)
-{
-  GSList *esources;
-
-  dprintf ("appointment_sources_changed: updating ...\n");
-
-  esources = calendar_sources_get_appointment_sources (client->priv->calendar_sources);
-
-  client->priv->appointment_sources = 
-    calendar_client_update_sources_list (client,
-                                        client->priv->appointment_sources,
-                                        esources,
-                                        signals [APPOINTMENTS_CHANGED]);
-
-  load_calendars (client, CALENDAR_EVENT_APPOINTMENT);
-  calendar_client_update_appointments (client);
-}
-
-static void
-calendar_client_task_sources_changed (CalendarClient  *client)
-{
-  GSList *esources;
-
-  dprintf ("task_sources_changed: updating ...\n");
-
-  esources = calendar_sources_get_task_sources (client->priv->calendar_sources);
-
-  client->priv->task_sources = 
-    calendar_client_update_sources_list (client,
-                                        client->priv->task_sources,
-                                        esources,
-                                        signals [TASKS_CHANGED]);
-
-  load_calendars (client, CALENDAR_EVENT_TASK);
-  calendar_client_update_tasks (client);
-}
-
-void
-calendar_client_get_date (CalendarClient *client,
-                          guint          *year,
-                          guint          *month,
-                          guint          *day)
-{
-  g_return_if_fail (CALENDAR_IS_CLIENT (client));
-
-  if (year)
-    *year = client->priv->year;
-
-  if (month)
-    *month = client->priv->month;
-
-  if (day)
-    *day = client->priv->day;
-}
-
-void
-calendar_client_select_month (CalendarClient *client,
-                             guint           month,
-                             guint           year)
-{
-  g_return_if_fail (CALENDAR_IS_CLIENT (client));
-  g_return_if_fail (month <= 11);
-
-  if (client->priv->year != year || client->priv->month != month)
-    {
-      client->priv->month = month;
-      client->priv->year  = year;
-
-      calendar_client_update_appointments (client);
-      calendar_client_update_tasks (client);
-
-      g_object_freeze_notify (G_OBJECT (client));
-      g_object_notify (G_OBJECT (client), "month");
-      g_object_notify (G_OBJECT (client), "year");
-      g_object_thaw_notify (G_OBJECT (client));
-    }
-}
-
-void
-calendar_client_select_day (CalendarClient *client,
-                           guint           day)
-{
-  g_return_if_fail (CALENDAR_IS_CLIENT (client));
-  g_return_if_fail (day <= 31);
-
-  if (client->priv->day != day)
-    {
-      client->priv->day = day;
-
-      /* don't need to update appointments unless
-       * the selected month changes
-       */
-#ifdef FIX_BROKEN_TASKS_QUERY
-      calendar_client_update_tasks (client);
-#endif
-
-      g_object_notify (G_OBJECT (client), "day");
-    }
-}
-
-typedef struct
-{
-  CalendarClient *client;
-  GSList         *events;
-  time_t          start_time;
-  time_t          end_time;
-} FilterData;
-
-typedef void (* CalendarEventFilterFunc) (const char    *uid,
-                                         CalendarEvent *event,
-                                         FilterData    *filter_data);
-
-static void
-filter_appointment (const char    *uid,
-                   CalendarEvent *event,
-                   FilterData    *filter_data)
-{
-  GSList *occurrences, *l;
-
-  if (event->type != CALENDAR_EVENT_APPOINTMENT)
-    return;
-
-  occurrences = CALENDAR_APPOINTMENT (event)->occurrences;
-  CALENDAR_APPOINTMENT (event)->occurrences = NULL;
-
-  for (l = occurrences; l; l = l->next)
-    {
-      CalendarOccurrence *occurrence = l->data;
-      time_t start_time = occurrence->start_time;
-      time_t end_time   = occurrence->end_time;
-
-      if ((start_time >= filter_data->start_time &&
-           start_time < filter_data->end_time) ||
-          (start_time <= filter_data->start_time &&
-           (end_time - 1) > filter_data->start_time))
-       {
-         CalendarEvent *new_event;
-
-         new_event = calendar_event_copy (event);
-             
-         CALENDAR_APPOINTMENT (new_event)->start_time = occurrence->start_time;
-         CALENDAR_APPOINTMENT (new_event)->end_time   = occurrence->end_time;
-             
-         filter_data->events = g_slist_prepend (filter_data->events, new_event);
-       }
-    }
-
-  CALENDAR_APPOINTMENT (event)->occurrences = occurrences;
-}
-
-static void
-filter_task (const char    *uid,
-            CalendarEvent *event,
-            FilterData    *filter_data)
-{
-#ifdef FIX_BROKEN_TASKS_QUERY
-  CalendarTask *task;
-#endif
-
-  if (event->type != CALENDAR_EVENT_TASK)
-    return;
-
-#ifdef FIX_BROKEN_TASKS_QUERY
-  task = CALENDAR_TASK (event);
-
-  if (task->start_time && task->start_time > filter_data->start_time)
-    return;
-
-  if (task->completed_time && 
-      (task->completed_time < filter_data->start_time ||
-       task->completed_time > filter_data->end_time))
-    return;
-#endif /* FIX_BROKEN_TASKS_QUERY */
-
-  filter_data->events = g_slist_prepend (filter_data->events,
-                                        calendar_event_copy (event));
-}
-
-static GSList *
-calendar_client_filter_events (CalendarClient          *client,
-                              GSList                  *sources,
-                              CalendarEventFilterFunc  filter_func,
-                              time_t                   start_time,
-                              time_t                   end_time)
-{
-  FilterData  filter_data;
-  GSList     *l;
-  GSList     *retval;
-
-  if (!sources)
-    return NULL;
-
-  filter_data.client     = client;
-  filter_data.events     = NULL;
-  filter_data.start_time = start_time;
-  filter_data.end_time   = end_time;
-
-  retval = NULL;
-  for (l = sources; l; l = l->next)
-    {
-      CalendarClientSource *source = l->data;
-
-      if (source->query_completed)
-       {
-         filter_data.events = NULL;
-         g_hash_table_foreach (source->completed_query.events,
-                               (GHFunc) filter_func,
-                               &filter_data);
-
-         filter_data.events = g_slist_reverse (filter_data.events);
-
-         retval = g_slist_concat (retval, filter_data.events);
-       }
-    }
-
-  return retval;
-}
-
-GSList *
-calendar_client_get_events (CalendarClient    *client,
-                           CalendarEventType  event_mask)
-{
-  GSList *appointments;
-  GSList *tasks;
-  time_t  day_begin;
-  time_t  day_end;
-
-  g_return_val_if_fail (CALENDAR_IS_CLIENT (client), NULL);
-  g_return_val_if_fail (client->priv->day   != -1 &&
-                       client->priv->month != -1 &&
-                       client->priv->year  != -1, NULL);
-
-  day_begin = make_time_for_day_begin (client->priv->day,
-                                      client->priv->month,
-                                      client->priv->year);
-  day_end   = make_time_for_day_begin (client->priv->day + 1,
-                                      client->priv->month,
-                                      client->priv->year);
-
-  appointments = NULL;
-  if (event_mask & CALENDAR_EVENT_APPOINTMENT)
-    {
-      appointments = calendar_client_filter_events (client,
-                                                   client->priv->appointment_sources,
-                                                   filter_appointment,
-                                                   day_begin,
-                                                   day_end);
-    }
-
-  tasks = NULL;
-  if (event_mask & CALENDAR_EVENT_TASK)
-    {
-      tasks = calendar_client_filter_events (client,
-                                            client->priv->task_sources,
-                                            filter_task,
-                                            day_begin,
-                                            day_end);
-    }
-
-  return g_slist_concat (appointments, tasks);
-}
-
-static inline int
-day_from_time_t (time_t t)
-{
-  struct tm *tm = localtime (&t);
-
-  g_assert (tm == NULL || (tm->tm_mday >=1 && tm->tm_mday <= 31));
-
-  return tm ? tm->tm_mday : 0;
-}
-
-void
-calendar_client_foreach_appointment_day (CalendarClient  *client,
-                                        CalendarDayIter  iter_func,
-                                        gpointer         user_data)
-{
-  GSList   *appointments, *l;
-  gboolean  marked_days [32] = { FALSE, };
-  time_t    month_begin;
-  time_t    month_end;
-  int       i;
-
-  g_return_if_fail (CALENDAR_IS_CLIENT (client));
-  g_return_if_fail (iter_func != NULL);
-  g_return_if_fail (client->priv->month != -1 &&
-                   client->priv->year  != -1);
-
-  month_begin = make_time_for_day_begin (1,
-                                        client->priv->month,
-                                        client->priv->year);
-  month_end   = make_time_for_day_begin (1,
-                                        client->priv->month + 1,
-                                        client->priv->year);
-  
-  appointments = calendar_client_filter_events (client,
-                                               client->priv->appointment_sources,
-                                               filter_appointment,
-                                               month_begin,
-                                               month_end);
-  for (l = appointments; l; l = l->next)
-    {
-      CalendarAppointment *appointment = l->data;
-
-      if (appointment->start_time)
-        {
-          time_t day_time = appointment->start_time;
-
-          if (day_time >= month_begin)
-            marked_days [day_from_time_t (day_time)] = TRUE;
-      
-          if (appointment->end_time)
-            {
-              int day_offset;
-              int duration = appointment->end_time - appointment->start_time;
-             /* mark the days for the appointment, no need to add an extra one when duration is a multiple of 86400 */
-              for (day_offset = 1; day_offset <= duration / 86400 && duration != day_offset * 86400; day_offset++)
-                {
-                  time_t day_tm = appointment->start_time + day_offset * 86400;
-
-                  if (day_tm > month_end)
-                    break;
-                  if (day_tm >= month_begin)
-                    marked_days [day_from_time_t (day_tm)] = TRUE;
-                }
-            }
-        }
-      calendar_event_free (CALENDAR_EVENT (appointment));
-    }
-
-  g_slist_free (appointments);
-
-  for (i = 1; i < 32; i++)
-    {
-      if (marked_days [i])
-       iter_func (client, i, user_data);
-    }
-}
-
-void
-calendar_client_set_task_completed (CalendarClient *client,
-                                   char           *task_uid,
-                                   gboolean        task_completed,
-                                   guint           percent_complete)
-{
-  GSList              *l;
-  ECal                *esource;
-  icalcomponent       *ical;
-  icalproperty        *prop;
-  icalproperty_status  status;
-
-  g_return_if_fail (CALENDAR_IS_CLIENT (client));
-  g_return_if_fail (task_uid != NULL);
-  g_return_if_fail (task_completed == FALSE || percent_complete == 100);
-
-  ical = NULL;
-  esource = NULL;
-  for (l = client->priv->task_sources; l; l = l->next)
-    {
-      CalendarClientSource *source = l->data;
-
-      esource = source->source;
-      e_cal_get_object (esource, task_uid, NULL, &ical, NULL);
-      if (ical)
-       break;
-    }
-
-  if (!ical)
-    {
-      g_warning ("Cannot locate task with uid = '%s'\n", task_uid);
-      return;
-    }
-
-  g_assert (esource != NULL);
-
-  /* Completed time */
-  prop = icalcomponent_get_first_property (ical,
-                                          ICAL_COMPLETED_PROPERTY);
-  if (task_completed)
-    {
-      struct icaltimetype  completed_time;
-
-      completed_time = icaltime_current_time_with_zone (client->priv->zone);
-      if (!prop)
-       {
-         icalcomponent_add_property (ical,
-                                     icalproperty_new_completed (completed_time));
-       }
-      else
-       {
-         icalproperty_set_completed (prop, completed_time);
-       }
-    }
-  else if (prop)
-    {
-      icalcomponent_remove_property (ical, prop);
-    }
-
-  /* Percent complete */
-  prop = icalcomponent_get_first_property (ical,
-                                          ICAL_PERCENTCOMPLETE_PROPERTY);
-  if (!prop)
-    {
-      icalcomponent_add_property (ical,
-                                 icalproperty_new_percentcomplete (percent_complete));
-    }
-  else
-    {
-      icalproperty_set_percentcomplete (prop, percent_complete);
-    }
-
-  /* Status */
-  status = task_completed ? ICAL_STATUS_COMPLETED : ICAL_STATUS_NEEDSACTION;
-  prop = icalcomponent_get_first_property (ical, ICAL_STATUS_PROPERTY);
-  if (prop)
-    {
-      icalproperty_set_status (prop, status);
-    }
-  else
-    {
-      icalcomponent_add_property (ical,
-                                 icalproperty_new_status (status));
-    }
-
-  e_cal_modify_object (esource, ical, CALOBJ_MOD_ALL, NULL);
-}
diff --git a/src/calendar-client/calendar-client.h b/src/calendar-client/calendar-client.h
deleted file mode 100644 (file)
index 3ae3b2f..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- *     Mark McLoughlin  <mark@skynet.ie>
- *     William Jon McCann  <mccann@jhu.edu>
- *     Martin Grimme  <martin@pycage.de>
- *     Christian Kellner  <gicmo@xatom.net>
- */
-
-#ifndef __CALENDAR_CLIENT_H__
-#define __CALENDAR_CLIENT_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-typedef enum
-{
-  CALENDAR_EVENT_APPOINTMENT = 1 << 0,
-  CALENDAR_EVENT_TASK        = 1 << 1,
-  CALENDAR_EVENT_ALL         = (1 << 2) - 1
-} CalendarEventType;
-
-#define CALENDAR_TYPE_CLIENT        (calendar_client_get_type ())
-#define CALENDAR_CLIENT(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_CLIENT, CalendarClient))
-#define CALENDAR_CLIENT_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_CLIENT, CalendarClientClass))
-#define CALENDAR_IS_CLIENT(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_CLIENT))
-#define CALENDAR_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_CLIENT))
-#define CALENDAR_CLIENT_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_CLIENT, CalendarClientClass))
-
-typedef struct _CalendarClient        CalendarClient;
-typedef struct _CalendarClientClass   CalendarClientClass;
-typedef struct _CalendarClientPrivate CalendarClientPrivate;
-
-struct _CalendarClient
-{
-  GObject                parent;
-  CalendarClientPrivate *priv;
-};
-
-struct _CalendarClientClass
-{
-  GObjectClass    parent_class;
-
-  void         (* appointments_changed) (CalendarClient *client);
-  void         (* tasks_changed)        (CalendarClient *client);
-};
-
-
-typedef struct
-{
-  time_t start_time;
-  time_t end_time;
-} CalendarOccurrence;
-
-typedef struct
-{
-  char   *uid;
-  char   *rid;
-  char   *uri;
-  char   *summary;
-  char   *description;
-  char   *color_string;
-  time_t  start_time;
-  time_t  end_time;
-  guint   is_all_day : 1;
-
-  /* Only used internally */
-  GSList *occurrences;
-} CalendarAppointment;
-
-typedef struct
-{
-  char  *uid;
-  char  *summary;
-  char  *description;
-  char  *color_string;
-  char  *url;
-  time_t start_time;
-  time_t due_time;
-  guint  percent_complete;
-  time_t completed_time;
-  int    priority;
-} CalendarTask;
-
-typedef struct
-{
-  union
-  {
-    CalendarAppointment appointment;
-    CalendarTask        task;
-  } event;
-  CalendarEventType type;
-} CalendarEvent;
-
-#define CALENDAR_EVENT(e)       ((CalendarEvent *)(e))
-#define CALENDAR_APPOINTMENT(e) ((CalendarAppointment *)(e))
-#define CALENDAR_TASK(e)        ((CalendarTask *)(e))
-
-typedef void (* CalendarDayIter) (CalendarClient *client,
-                                 guint           day,
-                                 gpointer        user_data);
-
-
-GType           calendar_client_get_type                (void) G_GNUC_CONST;
-CalendarClient *calendar_client_new                     (void);
-
-void            calendar_client_get_date                (CalendarClient      *client,
-                                                        guint               *year,
-                                                         guint               *month,
-                                                        guint               *day);
-void            calendar_client_select_month            (CalendarClient      *client,
-                                                        guint                month,
-                                                        guint                year);
-void            calendar_client_select_day              (CalendarClient      *client,
-                                                        guint                day);
-
-GSList         *calendar_client_get_events              (CalendarClient      *client,
-                                                        CalendarEventType    event_mask);
-void            calendar_client_foreach_appointment_day (CalendarClient      *client,
-                                                        CalendarDayIter      iter_func,
-                                                        gpointer             user_data);
-
-void            calendar_client_set_task_completed       (CalendarClient     *client,
-                                                         char               *task_uid,
-                                                         gboolean            task_completed,
-                                                         guint               percent_complete);
-
-void calendar_event_free (CalendarEvent *event);
-
-G_END_DECLS
-
-#endif /* __CALENDAR_CLIENT_H__ */
diff --git a/src/calendar-client/calendar-debug.h b/src/calendar-client/calendar-debug.h
deleted file mode 100644 (file)
index 61ad156..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- *     Mark McLoughlin  <mark@skynet.ie>
- */
-
-#ifndef __CALENDAR_DEBUG_H__
-#define __CALENDAR_DEBUG_H__
-
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-#ifdef CALENDAR_ENABLE_DEBUG
-
-#include <stdio.h>
-
-#ifdef G_HAVE_ISO_VARARGS
-#  define dprintf(...) fprintf (stderr, __VA_ARGS__);
-#elif defined(G_HAVE_GNUC_VARARGS)
-#  define dprintf(args...) fprintf (stderr, args);
-#endif
-
-#else /* if !defined (CALENDAR_DEBUG) */
-
-#ifdef G_HAVE_ISO_VARARGS
-#  define dprintf(...)
-#elif defined(G_HAVE_GNUC_VARARGS)
-#  define dprintf(args...)
-#endif
-
-#endif /* CALENDAR_ENABLE_DEBUG */
-
-G_END_DECLS
-
-#endif /* __CALENDAR_DEBUG_H__ */
diff --git a/src/calendar-client/calendar-sources.c b/src/calendar-client/calendar-sources.c
deleted file mode 100644 (file)
index fa1fcac..0000000
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- *     Mark McLoughlin  <mark@skynet.ie>
- *     William Jon McCann  <mccann@jhu.edu>
- *     Martin Grimme  <martin@pycage.de>
- *     Christian Kellner  <gicmo@xatom.net>
- */
-
-#include <config.h>
-
-#include "calendar-sources.h"
-
-#include <libintl.h>
-#include <string.h>
-#include <gconf/gconf-client.h>
-#define HANDLE_LIBICAL_MEMORY
-#include <libecal/e-cal.h>
-#include <libedataserver/e-source-list.h>
-#include <libedataserverui/e-passwords.h>
-
-#undef CALENDAR_ENABLE_DEBUG
-#include "calendar-debug.h"
-
-#ifndef _
-#define _(x) gettext(x)
-#endif
-
-#ifndef N_
-#define N_(x) x
-#endif
-
-#define CALENDAR_SOURCES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesPrivate))
-
-#define CALENDAR_SOURCES_EVO_DIR                          "/apps/evolution"
-#define CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY          CALENDAR_SOURCES_EVO_DIR "/calendar/sources"
-#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/display"
-#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR "/selected_calendars"
-#define CALENDAR_SOURCES_TASK_SOURCES_KEY                 CALENDAR_SOURCES_EVO_DIR "/tasks/sources"
-#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR        CALENDAR_SOURCES_EVO_DIR "/calendar/tasks"
-#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY        CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR "/selected_tasks"
-
-typedef struct _CalendarSourceData CalendarSourceData;
-
-struct _CalendarSourceData
-{
-  ECalSourceType   source_type;
-  CalendarSources *sources;
-  guint            changed_signal;
-
-  GSList          *clients;
-  GSList          *selected_sources;
-  ESourceList     *esource_list;
-
-  guint            selected_sources_listener;
-  char            *selected_sources_dir;
-
-  guint            timeout_id;
-
-  guint            loaded : 1;
-};
-
-struct _CalendarSourcesPrivate
-{
-  CalendarSourceData  appointment_sources;
-  CalendarSourceData  task_sources;
-
-  GConfClient        *gconf_client;
-};
-
-static void calendar_sources_class_init (CalendarSourcesClass *klass);
-static void calendar_sources_init       (CalendarSources      *sources);
-static void calendar_sources_finalize   (GObject             *object);
-
-static void backend_died_cb (ECal *client, CalendarSourceData *source_data);
-static void calendar_sources_esource_list_changed (ESourceList        *source_list,
-                                                   CalendarSourceData *source_data);
-
-enum
-{
-  APPOINTMENT_SOURCES_CHANGED,
-  TASK_SOURCES_CHANGED,
-  LAST_SIGNAL
-};
-static guint signals [LAST_SIGNAL] = { 0, };
-
-static GObjectClass    *parent_class = NULL;
-static CalendarSources *calendar_sources_singleton = NULL;
-
-GType
-calendar_sources_get_type (void)
-{
-  static GType sources_type = 0;
-  
-  if (!sources_type)
-    {
-      static const GTypeInfo sources_info =
-      {
-       sizeof (CalendarSourcesClass),
-       NULL,           /* base_init */
-       NULL,           /* base_finalize */
-       (GClassInitFunc) calendar_sources_class_init,
-       NULL,           /* class_finalize */
-       NULL,           /* class_data */
-       sizeof (CalendarSources),
-       0,              /* n_preallocs */
-       (GInstanceInitFunc) calendar_sources_init,
-      };
-      
-      sources_type = g_type_register_static (G_TYPE_OBJECT,
-                                            "CalendarSources",
-                                            &sources_info, 0);
-    }
-  
-  return sources_type;
-}
-
-static void
-calendar_sources_class_init (CalendarSourcesClass *klass)
-{
-  GObjectClass *gobject_class = (GObjectClass *) klass;
-
-  parent_class = g_type_class_peek_parent (klass);
-
-  gobject_class->finalize = calendar_sources_finalize;
-
-  g_type_class_add_private (klass, sizeof (CalendarSourcesPrivate));
-
-  signals [APPOINTMENT_SOURCES_CHANGED] =
-    g_signal_new ("appointment-sources-changed",
-                 G_TYPE_FROM_CLASS (gobject_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (CalendarSourcesClass,
-                                  appointment_sources_changed),
-                 NULL,
-                 NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
-
-  signals [TASK_SOURCES_CHANGED] =
-    g_signal_new ("task-sources-changed",
-                 G_TYPE_FROM_CLASS (gobject_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (CalendarSourcesClass,
-                                  task_sources_changed),
-                 NULL,
-                 NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
-}
-
-static void
-calendar_sources_init (CalendarSources *sources)
-{
-  sources->priv = CALENDAR_SOURCES_GET_PRIVATE (sources);
-
-  sources->priv->appointment_sources.source_type    = E_CAL_SOURCE_TYPE_EVENT;
-  sources->priv->appointment_sources.sources        = sources;
-  sources->priv->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED];
-  sources->priv->appointment_sources.timeout_id     = 0;
-
-  sources->priv->task_sources.source_type    = E_CAL_SOURCE_TYPE_TODO;
-  sources->priv->task_sources.sources        = sources;
-  sources->priv->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED];
-  sources->priv->task_sources.timeout_id     = 0;
-
-  sources->priv->gconf_client = gconf_client_get_default ();
-}
-
-static void
-calendar_sources_finalize_source_data (CalendarSources    *sources,
-                                      CalendarSourceData *source_data)
-{
-  if (source_data->loaded)
-    {
-      GSList *l;
-
-      if (source_data->selected_sources_dir)
-       {
-         gconf_client_remove_dir (sources->priv->gconf_client,
-                                  source_data->selected_sources_dir,
-                                  NULL);
-
-         g_free (source_data->selected_sources_dir);
-         source_data->selected_sources_dir = NULL;
-       }
-
-      if (source_data->selected_sources_listener)
-       {
-         gconf_client_notify_remove (sources->priv->gconf_client,
-                                     source_data->selected_sources_listener);
-         source_data->selected_sources_listener = 0;
-       }
-
-      for (l = source_data->clients; l; l = l->next)
-        {
-          g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
-                                                G_CALLBACK (backend_died_cb),
-                                                source_data);
-          g_object_unref (l->data);
-        }
-      g_slist_free (source_data->clients);
-      source_data->clients = NULL;
-
-      if (source_data->esource_list)
-        {
-          g_signal_handlers_disconnect_by_func (source_data->esource_list,
-                                                G_CALLBACK (calendar_sources_esource_list_changed),
-                                                source_data);
-          g_object_unref (source_data->esource_list);
-       }
-      source_data->esource_list = NULL;
-
-      for (l = source_data->selected_sources; l; l = l->next)
-       g_free (l->data);
-      g_slist_free (source_data->selected_sources);
-      source_data->selected_sources = NULL;
-
-      if (source_data->timeout_id != 0)
-        {
-          g_source_remove (source_data->timeout_id);
-          source_data->timeout_id = 0;
-        }
-
-      source_data->loaded = FALSE;
-    }
-}
-
-static void
-calendar_sources_finalize (GObject *object)
-{
-  CalendarSources *sources = CALENDAR_SOURCES (object);
-
-  calendar_sources_finalize_source_data (sources, &sources->priv->appointment_sources);
-  calendar_sources_finalize_source_data (sources, &sources->priv->task_sources);
-
-  if (sources->priv->gconf_client)
-    g_object_unref (sources->priv->gconf_client);
-  sources->priv->gconf_client = NULL;
-
-  if (G_OBJECT_CLASS (parent_class)->finalize)
-    G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-CalendarSources *
-calendar_sources_get (void)
-{
-  gpointer singleton_location = &calendar_sources_singleton;
-
-  if (calendar_sources_singleton)
-    return g_object_ref (calendar_sources_singleton);
-
-  calendar_sources_singleton = g_object_new (CALENDAR_TYPE_SOURCES, NULL);
-  g_object_add_weak_pointer (G_OBJECT (calendar_sources_singleton),
-                            singleton_location);
-
-  return calendar_sources_singleton;
-}
-
-static gboolean
-is_source_selected (ESource *esource,
-                   GSList  *selected_sources)
-{
-  const char *uid;
-  GSList     *l;
-
-  uid = e_source_peek_uid (esource);
-
-  for (l = selected_sources; l; l = l->next)
-    {
-      const char *source = l->data;
-
-      if (!strcmp (source, uid))
-       return TRUE;
-    }
-
-  return FALSE;
-}
-
-static char *
-auth_func_cb (ECal       *ecal,
-             const char *prompt,
-             const char *key,
-             gpointer    user_data)
-{
-       ESource *source;
-       const gchar *auth_domain;
-       const gchar *component_name;
-
-       source = e_cal_get_source (ecal);
-       auth_domain = e_source_get_property (source, "auth-domain");
-       component_name = auth_domain ? auth_domain : "Calendar";
-
-       return e_passwords_get_password (component_name, key);
-}
-
-/* The clients are just created here but not loaded */
-static ECal *
-get_ecal_from_source (ESource        *esource,
-                     ECalSourceType  source_type,
-                     GSList         *existing_clients)
-{
-  ECal *retval;
-
-  if (existing_clients)
-    {
-      GSList *l;
-
-      for (l = existing_clients; l; l = l->next)
-       {
-         ECal *client = E_CAL (l->data);
-
-         if (e_source_equal (esource, e_cal_get_source (client)))
-           {
-             dprintf ("        load_esource: found existing source ... returning that\n");
-
-             return g_object_ref (client);
-           }
-       }
-    }
-
-  retval = e_cal_new (esource, source_type);
-  if (!retval)
-    {
-      g_warning ("Could not load source '%s' from '%s'\n",
-                e_source_peek_name (esource),
-                e_source_peek_relative_uri (esource));
-      return NULL;
-    }
-
-  e_cal_set_auth_func (retval, auth_func_cb, NULL);
-
-  return retval;
-}
-
-/* - Order doesn't matter
- * - Can just compare object pointers since we
- *   re-use client connections
- */
-static gboolean
-compare_ecal_lists (GSList *a,
-                   GSList *b)
-{
-  GSList *l;
-
-  if (g_slist_length (a) != g_slist_length (b))
-    return FALSE;
-
-  for (l = a; l; l = l->next)
-    {
-      if (!g_slist_find (b, l->data))
-       return FALSE;
-    }
-
-  return TRUE;
-}
-
-static inline void
-debug_dump_selected_sources (GSList *selected_sources)
-{
-#ifdef CALENDAR_ENABLE_DEBUG
-  GSList *l;
-
-  dprintf ("Selected sources:\n");
-  for (l = selected_sources; l; l = l->next)
-    {
-      char *source = l->data;
-
-      dprintf ("  %s\n", source);
-    }
-  dprintf ("\n");
-#endif
-}
-
-static inline void
-debug_dump_ecal_list (GSList *ecal_list)
-{
-#ifdef CALENDAR_ENABLE_DEBUG
-  GSList *l;
-
-  dprintf ("Loaded clients:\n");
-  for (l = ecal_list; l; l = l->next)
-    {
-      ECal    *client = l->data;
-      ESource *source = e_cal_get_source (client);
-
-      dprintf ("  %s %s %s\n",
-              e_source_peek_uid (source),
-              e_source_peek_name (source),
-              e_cal_get_uri (client));
-    }
-#endif
-}
-
-static void
-calendar_sources_load_esource_list (CalendarSourceData *source_data);
-
-static gboolean
-backend_restart (gpointer data)
-{
-  CalendarSourceData *source_data = data;
-
-  calendar_sources_load_esource_list (source_data);
-
-  source_data->timeout_id = 0;
-    
-  return FALSE;
-}
-
-static void
-backend_died_cb (ECal *client, CalendarSourceData *source_data)
-{
-  const char *uristr;
-
-  source_data->clients = g_slist_remove (source_data->clients, client);
-  if (g_slist_length (source_data->clients) < 1) 
-    {
-      g_slist_free (source_data->clients);
-      source_data->clients = NULL;
-    }
-  uristr = e_cal_get_uri (client);
-  g_warning ("The calendar backend for %s has crashed.", uristr);
-
-  if (source_data->timeout_id != 0)
-    {
-      g_source_remove (source_data->timeout_id);
-      source_data->timeout_id = 0;
-    }
-
-  source_data->timeout_id = g_timeout_add_seconds (2, backend_restart,
-                                                  source_data);
-}
-
-static void
-calendar_sources_load_esource_list (CalendarSourceData *source_data)
-{
-  GSList  *clients = NULL;
-  GSList  *groups, *l;
-  gboolean emit_signal = FALSE;
-
-  g_return_if_fail (source_data->esource_list != NULL);
-
-  debug_dump_selected_sources (source_data->selected_sources);
-
-  dprintf ("Source groups:\n");
-  groups = e_source_list_peek_groups (source_data->esource_list);
-  for (l = groups; l; l = l->next)
-    {
-      GSList *esources, *s;
-
-      dprintf ("  %s\n", e_source_group_peek_uid (l->data));
-      dprintf ("    sources:\n");
-
-      esources = e_source_group_peek_sources (l->data);
-      for (s = esources; s; s = s->next)
-       {
-         ESource *esource = E_SOURCE (s->data);
-         ECal    *client;
-
-         dprintf ("      type = '%s' uid = '%s', name = '%s', relative uri = '%s': \n",
-                   source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task",
-                  e_source_peek_uid (esource),
-                  e_source_peek_name (esource),
-                  e_source_peek_relative_uri (esource));
-
-         if (is_source_selected (esource, source_data->selected_sources) &&
-             (client = get_ecal_from_source (esource, source_data->source_type, source_data->clients)))
-           {
-             clients = g_slist_prepend (clients, client);
-           }
-       }
-    }
-  dprintf ("\n");
-
-  if (source_data->loaded && 
-      !compare_ecal_lists (source_data->clients, clients))
-    emit_signal = TRUE;
-
-  for (l = source_data->clients; l; l = l->next)
-    {
-      g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
-                                            G_CALLBACK (backend_died_cb),
-                                            source_data);
-
-      g_object_unref (l->data);
-    }
-  g_slist_free (source_data->clients);
-  source_data->clients = g_slist_reverse (clients);
-
-  /* connect to backend_died after we disconnected the previous signal
-   * handlers. If we do it before, we'll lose some handlers (for clients that
-   * were already there before) */
-  for (l = source_data->clients; l; l = l->next)
-    {
-      g_signal_connect (G_OBJECT (l->data), "backend_died",
-                        G_CALLBACK (backend_died_cb), source_data);
-    }
-
-  if (emit_signal) 
-    {
-      dprintf ("Emitting %s-sources-changed signal\n",
-              source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task");
-      g_signal_emit (source_data->sources, source_data->changed_signal, 0);
-    }
-
-  debug_dump_ecal_list (source_data->clients);
-}
-
-static void
-calendar_sources_esource_list_changed (ESourceList        *source_list,
-                                      CalendarSourceData *source_data)
-                                      
-{
-  dprintf ("ESourceList changed, reloading\n");
-
-  calendar_sources_load_esource_list (source_data);
-}
-
-static void
-calendar_sources_selected_sources_notify (GConfClient        *client,
-                                         guint               cnx_id,
-                                         GConfEntry         *entry,
-                                         CalendarSourceData *source_data)
-{
-  GSList *l;
-
-  if (!entry->value ||
-      entry->value->type != GCONF_VALUE_LIST ||
-      gconf_value_get_list_type (entry->value) != GCONF_VALUE_STRING)
-    return;
-
-  dprintf ("Selected sources key (%s) changed, reloading\n", entry->key);
-
-  for (l = source_data->selected_sources; l; l = l->next)
-    g_free (l->data);
-  source_data->selected_sources = NULL;
-
-  for (l = gconf_value_get_list (entry->value); l; l = l->next)
-    {
-      const char *source = gconf_value_get_string (l->data);
-
-      source_data->selected_sources = 
-       g_slist_prepend (source_data->selected_sources,
-                        g_strdup (source));
-    }
-  source_data->selected_sources =
-    g_slist_reverse (source_data->selected_sources);
-
-  calendar_sources_load_esource_list (source_data);
-}
-
-static void
-calendar_sources_load_sources (CalendarSources    *sources,
-                              CalendarSourceData *source_data,
-                              const char         *sources_key,
-                              const char         *selected_sources_key,
-                              const char         *selected_sources_dir)
-{
-  GConfClient *gconf_client;
-  GError      *error;
-
-  dprintf ("---------------------------\n");
-  dprintf ("Loading sources:\n");
-  dprintf ("  sources_key: %s\n", sources_key);
-  dprintf ("  selected_sources_key: %s\n", selected_sources_key);
-  dprintf ("  selected_sources_dir: %s\n", selected_sources_dir);
-
-  gconf_client = sources->priv->gconf_client;
-
-  error = NULL;
-  source_data->selected_sources = gconf_client_get_list (gconf_client,
-                                                        selected_sources_key,
-                                                        GCONF_VALUE_STRING,
-                                                        &error);
-  if (error)
-    {
-      g_warning ("Failed to get selected sources from '%s': %s\n",
-                selected_sources_key,
-                error->message);
-      g_error_free (error);
-      return;
-    }
-
-  gconf_client_add_dir (gconf_client,
-                       selected_sources_dir,
-                       GCONF_CLIENT_PRELOAD_NONE,
-                       NULL);
-  source_data->selected_sources_dir = g_strdup (selected_sources_dir);
-
-  source_data->selected_sources_listener =
-    gconf_client_notify_add (gconf_client,
-                            selected_sources_dir,
-                            (GConfClientNotifyFunc) calendar_sources_selected_sources_notify,
-                            source_data, NULL, NULL);
-
-  source_data->esource_list = e_source_list_new_for_gconf (gconf_client, sources_key);
-  g_signal_connect (source_data->esource_list, "changed",
-                   G_CALLBACK (calendar_sources_esource_list_changed),
-                   source_data);
-
-  calendar_sources_load_esource_list (source_data);
-
-  source_data->loaded = TRUE;
-
-  dprintf ("---------------------------\n");
-}
-
-GSList *
-calendar_sources_get_appointment_sources (CalendarSources *sources)
-{
-  g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
-
-  if (!sources->priv->appointment_sources.loaded)
-    {
-      calendar_sources_load_sources (sources,
-                                    &sources->priv->appointment_sources,
-                                    CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY,
-                                    CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY,
-                                    CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR);
-    }
-  
-  return sources->priv->appointment_sources.clients;
-}
-
-GSList *
-calendar_sources_get_task_sources (CalendarSources *sources)
-{
-  g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
-
-  if (!sources->priv->task_sources.loaded)
-    {
-      calendar_sources_load_sources (sources,
-                                    &sources->priv->task_sources,
-                                    CALENDAR_SOURCES_TASK_SOURCES_KEY,
-                                    CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY,
-                                    CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR);
-    }
-
-  return sources->priv->task_sources.clients;
-}
diff --git a/src/calendar-client/calendar-sources.h b/src/calendar-client/calendar-sources.h
deleted file mode 100644 (file)
index 52741ab..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2004 Free Software Foundation, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- *
- * Authors:
- *     Mark McLoughlin  <mark@skynet.ie>
- *     William Jon McCann  <mccann@jhu.edu>
- *     Martin Grimme  <martin@pycage.de>
- *     Christian Kellner  <gicmo@xatom.net>
- */
-
-#ifndef __CALENDAR_SOURCES_H__
-#define __CALENDAR_SOURCES_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define CALENDAR_TYPE_SOURCES        (calendar_sources_get_type ())
-#define CALENDAR_SOURCES(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_SOURCES, CalendarSources))
-#define CALENDAR_SOURCES_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
-#define CALENDAR_IS_SOURCES(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_SOURCES))
-#define CALENDAR_IS_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_SOURCES))
-#define CALENDAR_SOURCES_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
-
-typedef struct _CalendarSources        CalendarSources;
-typedef struct _CalendarSourcesClass   CalendarSourcesClass;
-typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate;
-
-struct _CalendarSources
-{
-  GObject                 parent;
-  CalendarSourcesPrivate *priv;
-};
-
-struct _CalendarSourcesClass
-{
-  GObjectClass    parent_class;
-
-  void         (* appointment_sources_changed) (CalendarSources *sources);
-  void         (* task_sources_changed)        (CalendarSources *sources);
-};
-
-
-GType            calendar_sources_get_type                (void) G_GNUC_CONST;
-CalendarSources *calendar_sources_get                     (void);
-GSList          *calendar_sources_get_appointment_sources (CalendarSources *sources);
-GSList          *calendar_sources_get_task_sources        (CalendarSources *sources);
-
-G_END_DECLS
-
-#endif /* __CALENDAR_SOURCES_H__ */
diff --git a/src/calendar-server/README b/src/calendar-server/README
new file mode 100644 (file)
index 0000000..ad9b5e3
--- /dev/null
@@ -0,0 +1 @@
+Please keep in sync with gnome-panel.
diff --git a/src/calendar-server/calendar-debug.h b/src/calendar-server/calendar-debug.h
new file mode 100644 (file)
index 0000000..61ad156
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *     Mark McLoughlin  <mark@skynet.ie>
+ */
+
+#ifndef __CALENDAR_DEBUG_H__
+#define __CALENDAR_DEBUG_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#ifdef CALENDAR_ENABLE_DEBUG
+
+#include <stdio.h>
+
+#ifdef G_HAVE_ISO_VARARGS
+#  define dprintf(...) fprintf (stderr, __VA_ARGS__);
+#elif defined(G_HAVE_GNUC_VARARGS)
+#  define dprintf(args...) fprintf (stderr, args);
+#endif
+
+#else /* if !defined (CALENDAR_DEBUG) */
+
+#ifdef G_HAVE_ISO_VARARGS
+#  define dprintf(...)
+#elif defined(G_HAVE_GNUC_VARARGS)
+#  define dprintf(args...)
+#endif
+
+#endif /* CALENDAR_ENABLE_DEBUG */
+
+G_END_DECLS
+
+#endif /* __CALENDAR_DEBUG_H__ */
diff --git a/src/calendar-server/calendar-sources.c b/src/calendar-server/calendar-sources.c
new file mode 100644 (file)
index 0000000..fa1fcac
--- /dev/null
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *     Mark McLoughlin  <mark@skynet.ie>
+ *     William Jon McCann  <mccann@jhu.edu>
+ *     Martin Grimme  <martin@pycage.de>
+ *     Christian Kellner  <gicmo@xatom.net>
+ */
+
+#include <config.h>
+
+#include "calendar-sources.h"
+
+#include <libintl.h>
+#include <string.h>
+#include <gconf/gconf-client.h>
+#define HANDLE_LIBICAL_MEMORY
+#include <libecal/e-cal.h>
+#include <libedataserver/e-source-list.h>
+#include <libedataserverui/e-passwords.h>
+
+#undef CALENDAR_ENABLE_DEBUG
+#include "calendar-debug.h"
+
+#ifndef _
+#define _(x) gettext(x)
+#endif
+
+#ifndef N_
+#define N_(x) x
+#endif
+
+#define CALENDAR_SOURCES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesPrivate))
+
+#define CALENDAR_SOURCES_EVO_DIR                          "/apps/evolution"
+#define CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY          CALENDAR_SOURCES_EVO_DIR "/calendar/sources"
+#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/display"
+#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR "/selected_calendars"
+#define CALENDAR_SOURCES_TASK_SOURCES_KEY                 CALENDAR_SOURCES_EVO_DIR "/tasks/sources"
+#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR        CALENDAR_SOURCES_EVO_DIR "/calendar/tasks"
+#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY        CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR "/selected_tasks"
+
+typedef struct _CalendarSourceData CalendarSourceData;
+
+struct _CalendarSourceData
+{
+  ECalSourceType   source_type;
+  CalendarSources *sources;
+  guint            changed_signal;
+
+  GSList          *clients;
+  GSList          *selected_sources;
+  ESourceList     *esource_list;
+
+  guint            selected_sources_listener;
+  char            *selected_sources_dir;
+
+  guint            timeout_id;
+
+  guint            loaded : 1;
+};
+
+struct _CalendarSourcesPrivate
+{
+  CalendarSourceData  appointment_sources;
+  CalendarSourceData  task_sources;
+
+  GConfClient        *gconf_client;
+};
+
+static void calendar_sources_class_init (CalendarSourcesClass *klass);
+static void calendar_sources_init       (CalendarSources      *sources);
+static void calendar_sources_finalize   (GObject             *object);
+
+static void backend_died_cb (ECal *client, CalendarSourceData *source_data);
+static void calendar_sources_esource_list_changed (ESourceList        *source_list,
+                                                   CalendarSourceData *source_data);
+
+enum
+{
+  APPOINTMENT_SOURCES_CHANGED,
+  TASK_SOURCES_CHANGED,
+  LAST_SIGNAL
+};
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static GObjectClass    *parent_class = NULL;
+static CalendarSources *calendar_sources_singleton = NULL;
+
+GType
+calendar_sources_get_type (void)
+{
+  static GType sources_type = 0;
+  
+  if (!sources_type)
+    {
+      static const GTypeInfo sources_info =
+      {
+       sizeof (CalendarSourcesClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+       (GClassInitFunc) calendar_sources_class_init,
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
+       sizeof (CalendarSources),
+       0,              /* n_preallocs */
+       (GInstanceInitFunc) calendar_sources_init,
+      };
+      
+      sources_type = g_type_register_static (G_TYPE_OBJECT,
+                                            "CalendarSources",
+                                            &sources_info, 0);
+    }
+  
+  return sources_type;
+}
+
+static void
+calendar_sources_class_init (CalendarSourcesClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gobject_class->finalize = calendar_sources_finalize;
+
+  g_type_class_add_private (klass, sizeof (CalendarSourcesPrivate));
+
+  signals [APPOINTMENT_SOURCES_CHANGED] =
+    g_signal_new ("appointment-sources-changed",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (CalendarSourcesClass,
+                                  appointment_sources_changed),
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE,
+                 0);
+
+  signals [TASK_SOURCES_CHANGED] =
+    g_signal_new ("task-sources-changed",
+                 G_TYPE_FROM_CLASS (gobject_class),
+                 G_SIGNAL_RUN_LAST,
+                 G_STRUCT_OFFSET (CalendarSourcesClass,
+                                  task_sources_changed),
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE,
+                 0);
+}
+
+static void
+calendar_sources_init (CalendarSources *sources)
+{
+  sources->priv = CALENDAR_SOURCES_GET_PRIVATE (sources);
+
+  sources->priv->appointment_sources.source_type    = E_CAL_SOURCE_TYPE_EVENT;
+  sources->priv->appointment_sources.sources        = sources;
+  sources->priv->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED];
+  sources->priv->appointment_sources.timeout_id     = 0;
+
+  sources->priv->task_sources.source_type    = E_CAL_SOURCE_TYPE_TODO;
+  sources->priv->task_sources.sources        = sources;
+  sources->priv->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED];
+  sources->priv->task_sources.timeout_id     = 0;
+
+  sources->priv->gconf_client = gconf_client_get_default ();
+}
+
+static void
+calendar_sources_finalize_source_data (CalendarSources    *sources,
+                                      CalendarSourceData *source_data)
+{
+  if (source_data->loaded)
+    {
+      GSList *l;
+
+      if (source_data->selected_sources_dir)
+       {
+         gconf_client_remove_dir (sources->priv->gconf_client,
+                                  source_data->selected_sources_dir,
+                                  NULL);
+
+         g_free (source_data->selected_sources_dir);
+         source_data->selected_sources_dir = NULL;
+       }
+
+      if (source_data->selected_sources_listener)
+       {
+         gconf_client_notify_remove (sources->priv->gconf_client,
+                                     source_data->selected_sources_listener);
+         source_data->selected_sources_listener = 0;
+       }
+
+      for (l = source_data->clients; l; l = l->next)
+        {
+          g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
+                                                G_CALLBACK (backend_died_cb),
+                                                source_data);
+          g_object_unref (l->data);
+        }
+      g_slist_free (source_data->clients);
+      source_data->clients = NULL;
+
+      if (source_data->esource_list)
+        {
+          g_signal_handlers_disconnect_by_func (source_data->esource_list,
+                                                G_CALLBACK (calendar_sources_esource_list_changed),
+                                                source_data);
+          g_object_unref (source_data->esource_list);
+       }
+      source_data->esource_list = NULL;
+
+      for (l = source_data->selected_sources; l; l = l->next)
+       g_free (l->data);
+      g_slist_free (source_data->selected_sources);
+      source_data->selected_sources = NULL;
+
+      if (source_data->timeout_id != 0)
+        {
+          g_source_remove (source_data->timeout_id);
+          source_data->timeout_id = 0;
+        }
+
+      source_data->loaded = FALSE;
+    }
+}
+
+static void
+calendar_sources_finalize (GObject *object)
+{
+  CalendarSources *sources = CALENDAR_SOURCES (object);
+
+  calendar_sources_finalize_source_data (sources, &sources->priv->appointment_sources);
+  calendar_sources_finalize_source_data (sources, &sources->priv->task_sources);
+
+  if (sources->priv->gconf_client)
+    g_object_unref (sources->priv->gconf_client);
+  sources->priv->gconf_client = NULL;
+
+  if (G_OBJECT_CLASS (parent_class)->finalize)
+    G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+CalendarSources *
+calendar_sources_get (void)
+{
+  gpointer singleton_location = &calendar_sources_singleton;
+
+  if (calendar_sources_singleton)
+    return g_object_ref (calendar_sources_singleton);
+
+  calendar_sources_singleton = g_object_new (CALENDAR_TYPE_SOURCES, NULL);
+  g_object_add_weak_pointer (G_OBJECT (calendar_sources_singleton),
+                            singleton_location);
+
+  return calendar_sources_singleton;
+}
+
+static gboolean
+is_source_selected (ESource *esource,
+                   GSList  *selected_sources)
+{
+  const char *uid;
+  GSList     *l;
+
+  uid = e_source_peek_uid (esource);
+
+  for (l = selected_sources; l; l = l->next)
+    {
+      const char *source = l->data;
+
+      if (!strcmp (source, uid))
+       return TRUE;
+    }
+
+  return FALSE;
+}
+
+static char *
+auth_func_cb (ECal       *ecal,
+             const char *prompt,
+             const char *key,
+             gpointer    user_data)
+{
+       ESource *source;
+       const gchar *auth_domain;
+       const gchar *component_name;
+
+       source = e_cal_get_source (ecal);
+       auth_domain = e_source_get_property (source, "auth-domain");
+       component_name = auth_domain ? auth_domain : "Calendar";
+
+       return e_passwords_get_password (component_name, key);
+}
+
+/* The clients are just created here but not loaded */
+static ECal *
+get_ecal_from_source (ESource        *esource,
+                     ECalSourceType  source_type,
+                     GSList         *existing_clients)
+{
+  ECal *retval;
+
+  if (existing_clients)
+    {
+      GSList *l;
+
+      for (l = existing_clients; l; l = l->next)
+       {
+         ECal *client = E_CAL (l->data);
+
+         if (e_source_equal (esource, e_cal_get_source (client)))
+           {
+             dprintf ("        load_esource: found existing source ... returning that\n");
+
+             return g_object_ref (client);
+           }
+       }
+    }
+
+  retval = e_cal_new (esource, source_type);
+  if (!retval)
+    {
+      g_warning ("Could not load source '%s' from '%s'\n",
+                e_source_peek_name (esource),
+                e_source_peek_relative_uri (esource));
+      return NULL;
+    }
+
+  e_cal_set_auth_func (retval, auth_func_cb, NULL);
+
+  return retval;
+}
+
+/* - Order doesn't matter
+ * - Can just compare object pointers since we
+ *   re-use client connections
+ */
+static gboolean
+compare_ecal_lists (GSList *a,
+                   GSList *b)
+{
+  GSList *l;
+
+  if (g_slist_length (a) != g_slist_length (b))
+    return FALSE;
+
+  for (l = a; l; l = l->next)
+    {
+      if (!g_slist_find (b, l->data))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+static inline void
+debug_dump_selected_sources (GSList *selected_sources)
+{
+#ifdef CALENDAR_ENABLE_DEBUG
+  GSList *l;
+
+  dprintf ("Selected sources:\n");
+  for (l = selected_sources; l; l = l->next)
+    {
+      char *source = l->data;
+
+      dprintf ("  %s\n", source);
+    }
+  dprintf ("\n");
+#endif
+}
+
+static inline void
+debug_dump_ecal_list (GSList *ecal_list)
+{
+#ifdef CALENDAR_ENABLE_DEBUG
+  GSList *l;
+
+  dprintf ("Loaded clients:\n");
+  for (l = ecal_list; l; l = l->next)
+    {
+      ECal    *client = l->data;
+      ESource *source = e_cal_get_source (client);
+
+      dprintf ("  %s %s %s\n",
+              e_source_peek_uid (source),
+              e_source_peek_name (source),
+              e_cal_get_uri (client));
+    }
+#endif
+}
+
+static void
+calendar_sources_load_esource_list (CalendarSourceData *source_data);
+
+static gboolean
+backend_restart (gpointer data)
+{
+  CalendarSourceData *source_data = data;
+
+  calendar_sources_load_esource_list (source_data);
+
+  source_data->timeout_id = 0;
+    
+  return FALSE;
+}
+
+static void
+backend_died_cb (ECal *client, CalendarSourceData *source_data)
+{
+  const char *uristr;
+
+  source_data->clients = g_slist_remove (source_data->clients, client);
+  if (g_slist_length (source_data->clients) < 1) 
+    {
+      g_slist_free (source_data->clients);
+      source_data->clients = NULL;
+    }
+  uristr = e_cal_get_uri (client);
+  g_warning ("The calendar backend for %s has crashed.", uristr);
+
+  if (source_data->timeout_id != 0)
+    {
+      g_source_remove (source_data->timeout_id);
+      source_data->timeout_id = 0;
+    }
+
+  source_data->timeout_id = g_timeout_add_seconds (2, backend_restart,
+                                                  source_data);
+}
+
+static void
+calendar_sources_load_esource_list (CalendarSourceData *source_data)
+{
+  GSList  *clients = NULL;
+  GSList  *groups, *l;
+  gboolean emit_signal = FALSE;
+
+  g_return_if_fail (source_data->esource_list != NULL);
+
+  debug_dump_selected_sources (source_data->selected_sources);
+
+  dprintf ("Source groups:\n");
+  groups = e_source_list_peek_groups (source_data->esource_list);
+  for (l = groups; l; l = l->next)
+    {
+      GSList *esources, *s;
+
+      dprintf ("  %s\n", e_source_group_peek_uid (l->data));
+      dprintf ("    sources:\n");
+
+      esources = e_source_group_peek_sources (l->data);
+      for (s = esources; s; s = s->next)
+       {
+         ESource *esource = E_SOURCE (s->data);
+         ECal    *client;
+
+         dprintf ("      type = '%s' uid = '%s', name = '%s', relative uri = '%s': \n",
+                   source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task",
+                  e_source_peek_uid (esource),
+                  e_source_peek_name (esource),
+                  e_source_peek_relative_uri (esource));
+
+         if (is_source_selected (esource, source_data->selected_sources) &&
+             (client = get_ecal_from_source (esource, source_data->source_type, source_data->clients)))
+           {
+             clients = g_slist_prepend (clients, client);
+           }
+       }
+    }
+  dprintf ("\n");
+
+  if (source_data->loaded && 
+      !compare_ecal_lists (source_data->clients, clients))
+    emit_signal = TRUE;
+
+  for (l = source_data->clients; l; l = l->next)
+    {
+      g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
+                                            G_CALLBACK (backend_died_cb),
+                                            source_data);
+
+      g_object_unref (l->data);
+    }
+  g_slist_free (source_data->clients);
+  source_data->clients = g_slist_reverse (clients);
+
+  /* connect to backend_died after we disconnected the previous signal
+   * handlers. If we do it before, we'll lose some handlers (for clients that
+   * were already there before) */
+  for (l = source_data->clients; l; l = l->next)
+    {
+      g_signal_connect (G_OBJECT (l->data), "backend_died",
+                        G_CALLBACK (backend_died_cb), source_data);
+    }
+
+  if (emit_signal) 
+    {
+      dprintf ("Emitting %s-sources-changed signal\n",
+              source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task");
+      g_signal_emit (source_data->sources, source_data->changed_signal, 0);
+    }
+
+  debug_dump_ecal_list (source_data->clients);
+}
+
+static void
+calendar_sources_esource_list_changed (ESourceList        *source_list,
+                                      CalendarSourceData *source_data)
+                                      
+{
+  dprintf ("ESourceList changed, reloading\n");
+
+  calendar_sources_load_esource_list (source_data);
+}
+
+static void
+calendar_sources_selected_sources_notify (GConfClient        *client,
+                                         guint               cnx_id,
+                                         GConfEntry         *entry,
+                                         CalendarSourceData *source_data)
+{
+  GSList *l;
+
+  if (!entry->value ||
+      entry->value->type != GCONF_VALUE_LIST ||
+      gconf_value_get_list_type (entry->value) != GCONF_VALUE_STRING)
+    return;
+
+  dprintf ("Selected sources key (%s) changed, reloading\n", entry->key);
+
+  for (l = source_data->selected_sources; l; l = l->next)
+    g_free (l->data);
+  source_data->selected_sources = NULL;
+
+  for (l = gconf_value_get_list (entry->value); l; l = l->next)
+    {
+      const char *source = gconf_value_get_string (l->data);
+
+      source_data->selected_sources = 
+       g_slist_prepend (source_data->selected_sources,
+                        g_strdup (source));
+    }
+  source_data->selected_sources =
+    g_slist_reverse (source_data->selected_sources);
+
+  calendar_sources_load_esource_list (source_data);
+}
+
+static void
+calendar_sources_load_sources (CalendarSources    *sources,
+                              CalendarSourceData *source_data,
+                              const char         *sources_key,
+                              const char         *selected_sources_key,
+                              const char         *selected_sources_dir)
+{
+  GConfClient *gconf_client;
+  GError      *error;
+
+  dprintf ("---------------------------\n");
+  dprintf ("Loading sources:\n");
+  dprintf ("  sources_key: %s\n", sources_key);
+  dprintf ("  selected_sources_key: %s\n", selected_sources_key);
+  dprintf ("  selected_sources_dir: %s\n", selected_sources_dir);
+
+  gconf_client = sources->priv->gconf_client;
+
+  error = NULL;
+  source_data->selected_sources = gconf_client_get_list (gconf_client,
+                                                        selected_sources_key,
+                                                        GCONF_VALUE_STRING,
+                                                        &error);
+  if (error)
+    {
+      g_warning ("Failed to get selected sources from '%s': %s\n",
+                selected_sources_key,
+                error->message);
+      g_error_free (error);
+      return;
+    }
+
+  gconf_client_add_dir (gconf_client,
+                       selected_sources_dir,
+                       GCONF_CLIENT_PRELOAD_NONE,
+                       NULL);
+  source_data->selected_sources_dir = g_strdup (selected_sources_dir);
+
+  source_data->selected_sources_listener =
+    gconf_client_notify_add (gconf_client,
+                            selected_sources_dir,
+                            (GConfClientNotifyFunc) calendar_sources_selected_sources_notify,
+                            source_data, NULL, NULL);
+
+  source_data->esource_list = e_source_list_new_for_gconf (gconf_client, sources_key);
+  g_signal_connect (source_data->esource_list, "changed",
+                   G_CALLBACK (calendar_sources_esource_list_changed),
+                   source_data);
+
+  calendar_sources_load_esource_list (source_data);
+
+  source_data->loaded = TRUE;
+
+  dprintf ("---------------------------\n");
+}
+
+GSList *
+calendar_sources_get_appointment_sources (CalendarSources *sources)
+{
+  g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
+
+  if (!sources->priv->appointment_sources.loaded)
+    {
+      calendar_sources_load_sources (sources,
+                                    &sources->priv->appointment_sources,
+                                    CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY,
+                                    CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY,
+                                    CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR);
+    }
+  
+  return sources->priv->appointment_sources.clients;
+}
+
+GSList *
+calendar_sources_get_task_sources (CalendarSources *sources)
+{
+  g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
+
+  if (!sources->priv->task_sources.loaded)
+    {
+      calendar_sources_load_sources (sources,
+                                    &sources->priv->task_sources,
+                                    CALENDAR_SOURCES_TASK_SOURCES_KEY,
+                                    CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY,
+                                    CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR);
+    }
+
+  return sources->priv->task_sources.clients;
+}
diff --git a/src/calendar-server/calendar-sources.h b/src/calendar-server/calendar-sources.h
new file mode 100644 (file)
index 0000000..52741ab
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Authors:
+ *     Mark McLoughlin  <mark@skynet.ie>
+ *     William Jon McCann  <mccann@jhu.edu>
+ *     Martin Grimme  <martin@pycage.de>
+ *     Christian Kellner  <gicmo@xatom.net>
+ */
+
+#ifndef __CALENDAR_SOURCES_H__
+#define __CALENDAR_SOURCES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define CALENDAR_TYPE_SOURCES        (calendar_sources_get_type ())
+#define CALENDAR_SOURCES(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_SOURCES, CalendarSources))
+#define CALENDAR_SOURCES_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
+#define CALENDAR_IS_SOURCES(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_SOURCES))
+#define CALENDAR_IS_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_SOURCES))
+#define CALENDAR_SOURCES_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
+
+typedef struct _CalendarSources        CalendarSources;
+typedef struct _CalendarSourcesClass   CalendarSourcesClass;
+typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate;
+
+struct _CalendarSources
+{
+  GObject                 parent;
+  CalendarSourcesPrivate *priv;
+};
+
+struct _CalendarSourcesClass
+{
+  GObjectClass    parent_class;
+
+  void         (* appointment_sources_changed) (CalendarSources *sources);
+  void         (* task_sources_changed)        (CalendarSources *sources);
+};
+
+
+GType            calendar_sources_get_type                (void) G_GNUC_CONST;
+CalendarSources *calendar_sources_get                     (void);
+GSList          *calendar_sources_get_appointment_sources (CalendarSources *sources);
+GSList          *calendar_sources_get_task_sources        (CalendarSources *sources);
+
+G_END_DECLS
+
+#endif /* __CALENDAR_SOURCES_H__ */
diff --git a/src/calendar-server/gnome-shell-calendar-server.c b/src/calendar-server/gnome-shell-calendar-server.c
new file mode 100644 (file)
index 0000000..4d4d3a5
--- /dev/null
@@ -0,0 +1,1109 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ *
+ * Based on code from gnome-panel's clock-applet, file calendar-client.c, with Authors:
+ *
+ *     Mark McLoughlin  <mark@skynet.ie>
+ *     William Jon McCann  <mccann@jhu.edu>
+ *     Martin Grimme  <martin@pycage.de>
+ *     Christian Kellner  <gicmo@xatom.net>
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <gio/gio.h>
+
+#define HANDLE_LIBICAL_MEMORY
+#include <libecal/e-cal.h>
+#include <libecal/e-cal-time-util.h>
+#include <libecal/e-cal-recur.h>
+#include <libecal/e-cal-system-timezone.h>
+
+#define CALENDAR_CONFIG_PREFIX   "/apps/evolution/calendar"
+#define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone"
+
+#include "calendar-sources.h"
+
+/* Set the environment variable CALENDAR_SERVER_DEBUG to show debug */
+static void print_debug (const gchar *str, ...);
+
+#define BUS_NAME "org.gnome.Shell.CalendarServer"
+
+static const gchar introspection_xml[] =
+  "<node>"
+  "  <interface name='org.gnome.Shell.CalendarServer'>"
+  "    <method name='GetEvents'>"
+  "      <arg type='x' name='since' direction='in'/>"
+  "      <arg type='x' name='until' direction='in'/>"
+  "      <arg type='b' name='force_reload' direction='in'/>"
+  "      <arg type='a(sssbxxa{sv})' name='events' direction='out'/>"
+  "    </method>"
+  "    <signal name='Changed'/>"
+  "    <property name='Since' type='x' access='read'/>"
+  "    <property name='Until' type='x' access='read'/>"
+  "  </interface>"
+  "</node>";
+static GDBusNodeInfo *introspection_data = NULL;
+
+struct _App;
+typedef struct _App App;
+
+static GMainLoop    *loop = NULL;
+static gboolean      opt_replace = FALSE;
+static GOptionEntry  opt_entries[] = {
+  {"replace", 0, 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL},
+  {NULL }
+};
+static App *_global_app = NULL;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+  time_t start_time;
+  time_t end_time;
+} CalendarOccurrence;
+
+typedef struct
+{
+  char   *uid;
+  char   *rid;
+  char   *uri;
+  char   *summary;
+  char   *description;
+  char   *color_string;
+  time_t  start_time;
+  time_t  end_time;
+  guint   is_all_day : 1;
+
+  /* Only used internally */
+  GSList *occurrences;
+} CalendarAppointment;
+
+static time_t
+get_time_from_property (icalcomponent         *ical,
+                        icalproperty_kind      prop_kind,
+                        struct icaltimetype (* get_prop_func) (const icalproperty *prop),
+                        icaltimezone          *default_zone)
+{
+  icalproperty        *prop;
+  struct icaltimetype  ical_time;
+  icalparameter       *param;
+  icaltimezone        *timezone = NULL;
+
+  prop = icalcomponent_get_first_property (ical, prop_kind);
+  if (!prop)
+    return 0;
+
+  ical_time = get_prop_func (prop);
+
+  param = icalproperty_get_first_parameter (prop, ICAL_TZID_PARAMETER);
+  if (param)
+    timezone = icaltimezone_get_builtin_timezone_from_tzid (icalparameter_get_tzid (param));
+  else if (icaltime_is_utc (ical_time))
+    timezone = icaltimezone_get_utc_timezone ();
+  else
+    timezone = default_zone;
+
+  return icaltime_as_timet_with_zone (ical_time, timezone);
+}
+
+static char *
+get_ical_uid (icalcomponent *ical)
+{
+  return g_strdup (icalcomponent_get_uid (ical));
+}
+
+static char *
+get_ical_rid (icalcomponent *ical)
+{
+  icalproperty        *prop;
+  struct icaltimetype  ical_time;
+
+  prop = icalcomponent_get_first_property (ical, ICAL_RECURRENCEID_PROPERTY);
+  if (!prop)
+    return NULL;
+
+  ical_time = icalproperty_get_recurrenceid (prop);
+
+  return icaltime_is_valid_time (ical_time) && !icaltime_is_null_time (ical_time) ?
+    g_strdup (icaltime_as_ical_string (ical_time)) : NULL;
+}
+
+static char *
+get_ical_summary (icalcomponent *ical)
+{
+  icalproperty *prop;
+
+  prop = icalcomponent_get_first_property (ical, ICAL_SUMMARY_PROPERTY);
+  if (!prop)
+    return NULL;
+
+  return g_strdup (icalproperty_get_summary (prop));
+}
+
+static char *
+get_ical_description (icalcomponent *ical)
+{
+  icalproperty *prop;
+
+  prop = icalcomponent_get_first_property (ical, ICAL_DESCRIPTION_PROPERTY);
+  if (!prop)
+    return NULL;
+
+  return g_strdup (icalproperty_get_description (prop));
+}
+
+static inline time_t
+get_ical_start_time (icalcomponent *ical,
+                     icaltimezone  *default_zone)
+{
+  return get_time_from_property (ical,
+                                 ICAL_DTSTART_PROPERTY,
+                                 icalproperty_get_dtstart,
+                                 default_zone);
+}
+
+static inline time_t
+get_ical_end_time (icalcomponent *ical,
+                   icaltimezone  *default_zone)
+{
+  return get_time_from_property (ical,
+                                 ICAL_DTEND_PROPERTY,
+                                 icalproperty_get_dtend,
+                                 default_zone);
+}
+
+static gboolean
+get_ical_is_all_day (icalcomponent *ical,
+                     time_t         start_time,
+                     icaltimezone  *default_zone)
+{
+  icalproperty            *prop;
+  struct tm               *start_tm;
+  time_t                   end_time;
+  struct icaldurationtype  duration;
+  struct icaltimetype      start_icaltime;
+
+  start_icaltime = icalcomponent_get_dtstart (ical);
+  if (start_icaltime.is_date)
+    return TRUE;
+
+  start_tm = gmtime (&start_time);
+  if (start_tm->tm_sec  != 0 ||
+      start_tm->tm_min  != 0 ||
+      start_tm->tm_hour != 0)
+    return FALSE;
+
+  if ((end_time = get_ical_end_time (ical, default_zone)))
+    return (end_time - start_time) % 86400 == 0;
+
+  prop = icalcomponent_get_first_property (ical, ICAL_DURATION_PROPERTY);
+  if (!prop)
+    return FALSE;
+
+  duration = icalproperty_get_duration (prop);
+
+  return icaldurationtype_as_int (duration) % 86400 == 0;
+}
+
+static inline time_t
+get_ical_due_time (icalcomponent *ical,
+                   icaltimezone  *default_zone)
+{
+  return get_time_from_property (ical,
+                                 ICAL_DUE_PROPERTY,
+                                 icalproperty_get_due,
+                                 default_zone);
+}
+
+static inline time_t
+get_ical_completed_time (icalcomponent *ical,
+                         icaltimezone  *default_zone)
+{
+  return get_time_from_property (ical,
+                                 ICAL_COMPLETED_PROPERTY,
+                                 icalproperty_get_completed,
+                                 default_zone);
+}
+
+static char *
+get_source_color (ECal *esource)
+{
+  ESource *source;
+
+  g_return_val_if_fail (E_IS_CAL (esource), NULL);
+
+  source = e_cal_get_source (esource);
+
+  return g_strdup (e_source_peek_color_spec (source));
+}
+
+static gchar *
+get_source_uri (ECal *esource)
+{
+    ESource *source;
+    gchar   *string;
+    gchar  **list;
+
+    g_return_val_if_fail (E_IS_CAL (esource), NULL);
+
+    source = e_cal_get_source (esource);
+    string = g_strdup (e_source_get_uri (source));
+    if (string) {
+        list = g_strsplit (string, ":", 2);
+        g_free (string);
+
+        if (list[0]) {
+            string = g_strdup (list[0]);
+            g_strfreev (list);
+            return string;
+        }
+        g_strfreev (list);
+    }
+    return NULL;
+}
+
+static inline int
+null_safe_strcmp (const char *a,
+                  const char *b)
+{
+  return (!a && !b) ? 0 : (a && !b) || (!a && b) ? 1 : strcmp (a, b);
+}
+
+static inline gboolean
+calendar_appointment_equal (CalendarAppointment *a,
+                            CalendarAppointment *b)
+{
+  GSList *la, *lb;
+
+  if (g_slist_length (a->occurrences) != g_slist_length (b->occurrences))
+      return FALSE;
+
+  for (la = a->occurrences, lb = b->occurrences; la && lb; la = la->next, lb = lb->next)
+    {
+      CalendarOccurrence *oa = la->data;
+      CalendarOccurrence *ob = lb->data;
+
+      if (oa->start_time != ob->start_time ||
+          oa->end_time   != ob->end_time)
+        return FALSE;
+    }
+
+  return
+    null_safe_strcmp (a->uid,          b->uid)          == 0 &&
+    null_safe_strcmp (a->uri,          b->uri)          == 0 &&
+    null_safe_strcmp (a->summary,      b->summary)      == 0 &&
+    null_safe_strcmp (a->description,  b->description)  == 0 &&
+    null_safe_strcmp (a->color_string, b->color_string) == 0 &&
+    a->start_time == b->start_time                         &&
+    a->end_time   == b->end_time                           &&
+    a->is_all_day == b->is_all_day;
+}
+
+static void
+calendar_appointment_free (CalendarAppointment *appointment)
+{
+  GSList *l;
+
+  for (l = appointment->occurrences; l; l = l->next)
+    g_free (l->data);
+  g_slist_free (appointment->occurrences);
+  appointment->occurrences = NULL;
+
+  g_free (appointment->uid);
+  appointment->uid = NULL;
+
+  g_free (appointment->rid);
+  appointment->rid = NULL;
+
+  g_free (appointment->uri);
+  appointment->uri = NULL;
+
+  g_free (appointment->summary);
+  appointment->summary = NULL;
+
+  g_free (appointment->description);
+  appointment->description = NULL;
+
+  g_free (appointment->color_string);
+  appointment->color_string = NULL;
+
+  appointment->start_time = 0;
+  appointment->is_all_day = FALSE;
+}
+
+static void
+calendar_appointment_init (CalendarAppointment  *appointment,
+                           icalcomponent        *ical,
+                           ECal                 *cal,
+                           icaltimezone         *default_zone)
+{
+  appointment->uid          = get_ical_uid (ical);
+  appointment->rid          = get_ical_rid (ical);
+  appointment->uri          = get_source_uri (cal);
+  appointment->summary      = get_ical_summary (ical);
+  appointment->description  = get_ical_description (ical);
+  appointment->color_string = get_source_color (cal);
+  appointment->start_time   = get_ical_start_time (ical, default_zone);
+  appointment->end_time     = get_ical_end_time (ical, default_zone);
+  appointment->is_all_day   = get_ical_is_all_day (ical,
+                                                   appointment->start_time,
+                                                   default_zone);
+}
+
+static icaltimezone *
+resolve_timezone_id (const char *tzid,
+                     ECal       *source)
+{
+  icaltimezone *retval;
+
+  retval = icaltimezone_get_builtin_timezone_from_tzid (tzid);
+  if (!retval)
+    {
+      e_cal_get_timezone (source, tzid, &retval, NULL);
+    }
+
+  return retval;
+}
+
+static gboolean
+calendar_appointment_collect_occurrence (ECalComponent  *component,
+                                         time_t          occurrence_start,
+                                         time_t          occurrence_end,
+                                         gpointer        data)
+{
+  CalendarOccurrence *occurrence;
+  GSList **collect_loc = data;
+
+  occurrence             = g_new0 (CalendarOccurrence, 1);
+  occurrence->start_time = occurrence_start;
+  occurrence->end_time   = occurrence_end;
+
+  *collect_loc = g_slist_prepend (*collect_loc, occurrence);
+
+  return TRUE;
+}
+
+static void
+calendar_appointment_generate_occurrences (CalendarAppointment *appointment,
+                                           icalcomponent       *ical,
+                                           ECal                *cal,
+                                           time_t               start,
+                                           time_t               end,
+                                           icaltimezone        *default_zone)
+{
+  ECalComponent *ecal;
+
+  g_assert (appointment->occurrences == NULL);
+
+  ecal = e_cal_component_new ();
+  e_cal_component_set_icalcomponent (ecal,
+                                     icalcomponent_new_clone (ical));
+
+  e_cal_recur_generate_instances (ecal,
+                                  start,
+                                  end,
+                                  calendar_appointment_collect_occurrence,
+                                  &appointment->occurrences,
+                                  (ECalRecurResolveTimezoneFn) resolve_timezone_id,
+                                  cal,
+                                  default_zone);
+
+  g_object_unref (ecal);
+
+  appointment->occurrences = g_slist_reverse (appointment->occurrences);
+}
+
+static CalendarAppointment *
+calendar_appointment_new (icalcomponent        *ical,
+                          ECal                 *cal,
+                          icaltimezone         *default_zone)
+{
+  CalendarAppointment *appointment;
+
+  appointment = g_new0 (CalendarAppointment, 1);
+
+  calendar_appointment_init (appointment,
+                             ical,
+                             cal,
+                             default_zone);
+  return appointment;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+struct _App
+{
+  GDBusConnection *connection;
+
+  time_t since;
+  time_t until;
+
+  icaltimezone *zone;
+
+  CalendarSources *sources;
+  gulong sources_signal_id;
+
+  guint                zone_listener;
+  GConfClient         *gconf_client;
+
+  /* hash from uid to CalendarAppointment objects */
+  GHashTable *appointments;
+
+  gchar *timezone_location;
+
+  guint changed_timeout_id;
+
+  gboolean cache_invalid;
+
+  GList *live_views;
+};
+
+static void
+app_update_timezone (App *app)
+{
+  gchar *location;
+
+  location = e_cal_system_timezone_get_location ();
+  if (g_strcmp0 (location, app->timezone_location) != 0)
+    {
+      if (location == NULL)
+        app->zone = icaltimezone_get_utc_timezone ();
+      else
+        app->zone = icaltimezone_get_builtin_timezone (location);
+      g_free (app->timezone_location);
+      app->timezone_location = location;
+      print_debug ("Using timezone %s", app->timezone_location);
+    }
+}
+
+static gboolean
+on_app_schedule_changed_cb (gpointer user_data)
+{
+  App *app = user_data;
+  print_debug ("Emitting changed");
+  g_dbus_connection_emit_signal (app->connection,
+                                 NULL, /* destination_bus_name */
+                                 "/org/gnome/Shell/CalendarServer",
+                                 "org.gnome.Shell.CalendarServer",
+                                 "Changed",
+                                 NULL, /* no params */
+                                 NULL);
+  app->changed_timeout_id = 0;
+  return FALSE;
+}
+
+static void
+app_schedule_changed (App *app)
+{
+  print_debug ("Scheduling changed");
+  if (app->changed_timeout_id == 0)
+    {
+      app->changed_timeout_id = g_timeout_add (2000,
+                                               on_app_schedule_changed_cb,
+                                               app);
+    }
+}
+
+static void
+invalidate_cache (App *app)
+{
+  app->cache_invalid = TRUE;
+}
+
+static void
+on_objects_added (ECalView *view,
+                  GList    *objects,
+                  gpointer  user_data)
+{
+  App *app = user_data;
+  GList *l;
+
+  print_debug ("%s for calendar", G_STRFUNC);
+
+  for (l = objects; l != NULL; l = l->next)
+    {
+      icalcomponent *ical = l->data;
+      const char *uid;
+
+      uid = icalcomponent_get_uid (ical);
+
+      if (g_hash_table_lookup (app->appointments, uid) == NULL)
+        {
+          /* new appointment we don't know about => changed signal */
+          invalidate_cache (app);
+          app_schedule_changed (app);
+        }
+    }
+}
+
+static void
+on_objects_modified (ECalView *view,
+                     GList    *objects,
+                     gpointer  user_data)
+{
+  App *app = user_data;
+  print_debug ("%s for calendar", G_STRFUNC);
+  invalidate_cache (app);
+  app_schedule_changed (app);
+}
+
+static void
+on_objects_removed (ECalView *view,
+                    GList    *uids,
+                    gpointer  user_data)
+{
+  App *app = user_data;
+  print_debug ("%s for calendar", G_STRFUNC);
+  invalidate_cache (app);
+  app_schedule_changed (app);
+}
+
+static void
+app_load_events (App *app)
+{
+  GSList *sources;
+  GSList *l;
+  GList *ll;
+  gchar *since_iso8601;
+  gchar *until_iso8601;
+
+  /* out with the old */
+  g_hash_table_remove_all (app->appointments);
+  /* nuke existing views */
+  for (ll = app->live_views; ll != NULL; ll = ll->next)
+    {
+      ECalView *view = E_CAL_VIEW (ll->data);
+      g_signal_handlers_disconnect_by_func (view, on_objects_added, app);
+      g_signal_handlers_disconnect_by_func (view, on_objects_modified, app);
+      g_signal_handlers_disconnect_by_func (view, on_objects_removed, app);
+      e_cal_view_stop (view);
+      g_object_unref (view);
+    }
+  g_list_free (app->live_views);
+  app->live_views = NULL;
+
+  /* timezone could have changed */
+  app_update_timezone (app);
+
+  since_iso8601 = isodate_from_time_t (app->since);
+  until_iso8601 = isodate_from_time_t (app->until);
+
+  print_debug ("Loading events since %s until %s",
+               since_iso8601,
+               until_iso8601);
+
+  sources = calendar_sources_get_appointment_sources (app->sources);
+  for (l = sources; l != NULL; l = l->next)
+    {
+      ECal *cal = E_CAL (l->data);
+      GError *error;
+      gchar *query;
+      GList *objects;
+      GList *j;
+      ECalView *view;
+
+      error = NULL;
+      if (!e_cal_set_default_timezone (cal, app->zone, &error))
+        {
+          g_printerr ("Error setting timezone on calendar: %s\n", error->message);
+          g_error_free (error);
+          continue;
+        }
+
+      error = NULL;
+      if (!e_cal_open (cal, TRUE, &error))
+        {
+          g_printerr ("Error opening calendar: %s\n", error->message);
+          g_error_free (error);
+          continue;
+        }
+
+      query = g_strdup_printf ("occur-in-time-range? (make-time \"%s\") "
+                               "(make-time \"%s\")",
+                               since_iso8601,
+                               until_iso8601);
+      error = NULL;
+      objects = NULL;
+      if (!e_cal_get_object_list (cal,
+                                  query,
+                                  &objects,
+                                  &error))
+        {
+          g_printerr ("Error querying calendar: %s\n", error->message);
+          g_error_free (error);
+          g_free (query);
+          continue;
+        }
+
+      for (j = objects; j != NULL; j = j->next)
+        {
+          icalcomponent *ical = j->data;
+          CalendarAppointment *appointment;
+
+          appointment = calendar_appointment_new (ical, cal, app->zone);
+          if (appointment == NULL)
+            continue;
+
+          calendar_appointment_generate_occurrences (appointment,
+                                                     ical,
+                                                     cal,
+                                                     app->since,
+                                                     app->until,
+                                                     app->zone);
+          g_hash_table_insert (app->appointments, g_strdup (appointment->uid), appointment);
+        }
+
+      e_cal_free_object_list (objects);
+
+      error = NULL;
+      if (!e_cal_get_query (cal,
+                            query,
+                            &view,
+                            &error))
+        {
+          g_printerr ("Error setting up live-query on calendar: %s\n", error->message);
+          g_error_free (error);
+        }
+      else
+        {
+          g_signal_connect (view,
+                            "objects-added",
+                            G_CALLBACK (on_objects_added),
+                            app);
+          g_signal_connect (view,
+                            "objects-modified",
+                            G_CALLBACK (on_objects_modified),
+                            app);
+          g_signal_connect (view,
+                            "objects-removed",
+                            G_CALLBACK (on_objects_removed),
+                            app);
+          e_cal_view_start (view);
+          app->live_views = g_list_prepend (app->live_views, view);
+        }
+
+      g_free (query);
+    }
+  g_free (since_iso8601);
+  g_free (until_iso8601);
+  app->cache_invalid = FALSE;
+}
+
+static void
+on_appointment_sources_changed (CalendarSources *sources,
+                                gpointer         user_data)
+{
+  App *app = user_data;
+
+  print_debug ("Sources changed\n");
+  app_load_events (app);
+}
+
+static App *
+app_new (GDBusConnection *connection)
+{
+  App *app;
+
+  app = g_new0 (App, 1);
+  app->connection = g_object_ref (connection);
+  app->sources = calendar_sources_get ();
+  app->sources_signal_id = g_signal_connect (app->sources,
+                                             "appointment-sources-changed",
+                                             G_CALLBACK (on_appointment_sources_changed),
+                                             app);
+
+  app->appointments = g_hash_table_new_full (g_str_hash,
+                                             g_str_equal,
+                                             g_free,
+                                             (GDestroyNotify) calendar_appointment_free);
+
+  app_update_timezone (app);
+
+  return app;
+}
+
+static void
+app_free (App *app)
+{
+  GList *ll;
+  for (ll = app->live_views; ll != NULL; ll = ll->next)
+    {
+      ECalView *view = E_CAL_VIEW (ll->data);
+      g_signal_handlers_disconnect_by_func (view, on_objects_added, app);
+      g_signal_handlers_disconnect_by_func (view, on_objects_modified, app);
+      g_signal_handlers_disconnect_by_func (view, on_objects_removed, app);
+      e_cal_view_stop (view);
+      g_object_unref (view);
+    }
+  g_list_free (app->live_views);
+
+  g_free (app->timezone_location);
+
+  g_hash_table_unref (app->appointments);
+
+  g_object_unref (app->connection);
+  g_signal_handler_disconnect (app->sources,
+                               app->sources_signal_id);
+  g_object_unref (app->sources);
+
+  if (app->changed_timeout_id != 0)
+    g_source_remove (app->changed_timeout_id);
+
+  g_free (app);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+  App *app = user_data;
+
+  if (g_strcmp0 (method_name, "GetEvents") == 0)
+    {
+      GVariantBuilder builder;
+      GHashTableIter hash_iter;
+      CalendarAppointment *a;
+      gint64 since;
+      gint64 until;
+      gboolean force_reload;
+      gboolean window_changed;
+
+      g_variant_get (parameters,
+                     "(xxb)",
+                     &since,
+                     &until,
+                     &force_reload);
+
+      if (until < since)
+        {
+          g_dbus_method_invocation_return_dbus_error (invocation,
+                                                      "org.gnome.Shell.CalendarServer.Error.Failed",
+                                                      "until cannot be before since");
+          goto out;
+        }
+
+      print_debug ("Handling GetEvents (since=%" G_GINT64_FORMAT ", until=%" G_GINT64_FORMAT ", force_reload=%s)",
+                   since,
+                   until,
+                   force_reload ? "true" : "false");
+
+      window_changed = FALSE;
+      if (!(app->until == until && app->since == since))
+        {
+          GVariantBuilder *builder;
+          GVariantBuilder *invalidated_builder;
+
+          app->until = until;
+          app->since = since;
+          window_changed = TRUE;
+
+          builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
+          invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+          g_variant_builder_add (builder, "{sv}",
+                                 "Until", g_variant_new_int64 (app->until));
+          g_variant_builder_add (builder, "{sv}",
+                                 "Since", g_variant_new_int64 (app->since));
+          g_dbus_connection_emit_signal (app->connection,
+                                         NULL, /* destination_bus_name */
+                                         "/org/gnome/Shell/CalendarServer",
+                                         "org.freedesktop.DBus.Properties",
+                                         "PropertiesChanged",
+                                         g_variant_new ("(sa{sv}as)",
+                                                        "org.gnome.Shell.CalendarServer",
+                                                        builder,
+                                                        invalidated_builder),
+                                         NULL); /* GError** */
+        }
+
+      /* reload events if necessary */
+      if (window_changed || force_reload || app->cache_invalid)
+        {
+          app_load_events (app);
+        }
+
+      /* The a{sv} is used as an escape hatch in case we want to provide more
+       * information in the future without breaking ABI
+       */
+      g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssbxxa{sv})"));
+      g_hash_table_iter_init (&hash_iter, app->appointments);
+      while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &a))
+        {
+          GVariantBuilder extras_builder;
+          GSList *l;
+
+          for (l = a->occurrences; l; l = l->next)
+            {
+              CalendarOccurrence *o = l->data;
+              time_t start_time = o->start_time;
+              time_t end_time   = o->end_time;
+
+              if ((start_time >= app->since &&
+                   start_time < app->until) ||
+                  (start_time <= app->since &&
+                  (end_time - 1) > app->since))
+                {
+                  g_variant_builder_init (&extras_builder, G_VARIANT_TYPE ("a{sv}"));
+                  g_variant_builder_add (&builder,
+                                         "(sssbxxa{sv})",
+                                         a->uid,
+                                         a->summary != NULL ? a->summary : "",
+                                         a->description != NULL ? a->description : "",
+                                         (gboolean) a->is_all_day,
+                                         (gint64) start_time,
+                                         (gint64) end_time,
+                                         extras_builder);
+                }
+            }
+        }
+      g_dbus_method_invocation_return_value (invocation,
+                                             g_variant_new ("(a(sssbxxa{sv}))", &builder));
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+
+ out:
+  ;
+}
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+                     const gchar     *sender,
+                     const gchar     *object_path,
+                     const gchar     *interface_name,
+                     const gchar     *property_name,
+                     GError         **error,
+                     gpointer         user_data)
+{
+  App *app = user_data;
+  GVariant *ret;
+
+  ret = NULL;
+  if (g_strcmp0 (property_name, "Since") == 0)
+    {
+      ret = g_variant_new_int64 (app->since);
+    }
+  else if (g_strcmp0 (property_name, "Until") == 0)
+    {
+      ret = g_variant_new_int64 (app->until);
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+  return ret;
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+  handle_method_call,
+  handle_get_property,
+  NULL  /* handle_set_property */
+};
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+                 const gchar     *name,
+                 gpointer         user_data)
+{
+  GError *error;
+  guint registration_id;
+
+  _global_app = app_new (connection);
+
+  error = NULL;
+  registration_id = g_dbus_connection_register_object (connection,
+                                                       "/org/gnome/Shell/CalendarServer",
+                                                       introspection_data->interfaces[0],
+                                                       &interface_vtable,
+                                                       _global_app,
+                                                       NULL,  /* user_data_free_func */
+                                                       &error);
+  if (registration_id == 0)
+    {
+      g_printerr ("Error exporting object: %s (%s %d)",
+                  error->message,
+                  g_quark_to_string (error->domain),
+                  error->code);
+      g_error_free (error);
+      _exit (1);
+    }
+
+  print_debug ("Connected to the session bus");
+
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+              const gchar     *name,
+              gpointer         user_data)
+{
+  g_print ("gnome-shell-calendar-server[%d]: Lost (or failed to acquire) the name " BUS_NAME " - exiting\n",
+           (gint) getpid ());
+  g_main_loop_quit (loop);
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+                  const gchar     *name,
+                  gpointer         user_data)
+{
+  print_debug ("Acquired the name " BUS_NAME);
+}
+
+static gboolean
+stdin_channel_io_func (GIOChannel *source,
+                       GIOCondition condition,
+                       gpointer data)
+{
+  if (condition & G_IO_HUP)
+    {
+      g_print ("gnome-shell-calendar-server[%d]: Got HUP on stdin - exiting\n",
+               (gint) getpid ());
+      g_main_loop_quit (loop);
+    }
+  else
+    {
+      g_warning ("Unhandled condition %d on GIOChannel for stdin", condition);
+    }
+  return FALSE; /* remove source */
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+  GError *error;
+  GOptionContext *opt_context;
+  gint ret;
+  guint name_owner_id;
+  GIOChannel *stdin_channel;
+
+  ret = 1;
+  loop = NULL;
+  opt_context = NULL;
+  name_owner_id = 0;
+
+  g_type_init ();
+
+  introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+  g_assert (introspection_data != NULL);
+
+  opt_context = g_option_context_new ("gnome-shell calendar server");
+  g_option_context_add_main_entries (opt_context, opt_entries, NULL);
+  error = NULL;
+  if (!g_option_context_parse (opt_context, &argc, &argv, &error))
+    {
+      g_printerr ("Error parsing options: %s", error->message);
+      g_error_free (error);
+      goto out;
+    }
+
+  stdin_channel = g_io_channel_unix_new (STDIN_FILENO);
+  g_io_add_watch (stdin_channel,
+                  G_IO_HUP,
+                  stdin_channel_io_func,
+                  NULL);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  name_owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                                  BUS_NAME,
+                                  G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+                                   (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
+                                  on_bus_acquired,
+                                  on_name_acquired,
+                                  on_name_lost,
+                                  NULL,
+                                  NULL);
+
+  g_main_loop_run (loop);
+
+  ret = 0;
+
+ out:
+  if (stdin_channel != NULL)
+    g_io_channel_unref (stdin_channel);
+  if (_global_app != NULL)
+    app_free (_global_app);
+  if (name_owner_id != 0)
+    g_bus_unown_name (name_owner_id);
+  if (loop != NULL)
+    g_main_loop_unref (loop);
+  if (opt_context != NULL)
+    g_option_context_free (opt_context);
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+print_debug (const gchar *format, ...)
+{
+  gchar *s;
+  va_list ap;
+  gchar timebuf[64];
+  GTimeVal now;
+  time_t now_t;
+  struct tm broken_down;
+  static volatile gsize once_init_value = 0;
+  static gboolean show_debug = FALSE;
+  static guint pid = 0;
+
+  if (g_once_init_enter (&once_init_value))
+    {
+      show_debug = (g_getenv ("CALENDAR_SERVER_DEBUG") != NULL);
+      pid = getpid ();
+      g_once_init_leave (&once_init_value, 1);
+    }
+
+  if (!show_debug)
+    goto out;
+
+  g_get_current_time (&now);
+  now_t = now.tv_sec;
+  localtime_r (&now_t, &broken_down);
+  strftime (timebuf, sizeof timebuf, "%H:%M:%S", &broken_down);
+
+  va_start (ap, format);
+  s = g_strdup_vprintf (format, ap);
+  va_end (ap);
+
+  g_print ("gnome-shell-calendar-server[%d]: %s.%03d: %s\n", pid, timebuf, (gint) (now.tv_usec / 1000), s);
+  g_free (s);
+ out:
+  ;
+}
diff --git a/src/calendar-server/org.gnome.Shell.CalendarServer.service.in b/src/calendar-server/org.gnome.Shell.CalendarServer.service.in
new file mode 100644 (file)
index 0000000..5addce6
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.gnome.Shell.CalendarServer
+Exec=@libexecdir@/gnome-shell-calendar-server
index dd5e9674c3aa5d349e8eb9e385075db18d67df3f..e748ac65fdef379025a991fc512823681ea4f21a 100755 (executable)
@@ -197,7 +197,8 @@ def start_shell(perf_output=None):
     if running_from_source_tree:
         if os.environ.has_key('GI_TYPELIB_PATH'):
             typelib_dir = typelib_dir + ":" + os.environ.get('GI_TYPELIB_PATH')
-        env.update({'GNOME_SHELL_DATADIR'  : data_dir,
+        env.update({'GNOME_SHELL_BINDIR' : bin_dir,
+                    'GNOME_SHELL_DATADIR'  : data_dir,
                     'GI_TYPELIB_PATH'      : typelib_dir,
                     'GSETTINGS_SCHEMA_DIR' : data_dir })
     else:
diff --git a/src/shell-evolution-event-source.c b/src/shell-evolution-event-source.c
deleted file mode 100644 (file)
index 2982ddc..0000000
+++ /dev/null
@@ -1,265 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-#include "config.h"
-
-#include "calendar-client/calendar-client.h"
-#include "shell-evolution-event-source.h"
-
-
-struct _ShellEvolutionEventSourceClass
-{
-  GObjectClass parent_class;
-};
-
-struct _ShellEvolutionEventSource {
-  GObject parent;
-  CalendarClient *client;
-  /* The month that we are currently requesting events from */
-  gint req_year;
-  gint req_mon; /* starts at 1, not zero */
-};
-
-/* Signals */
-enum
-{
-  CHANGED_SIGNAL,
-  LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE (ShellEvolutionEventSource, shell_evolution_event_source, G_TYPE_OBJECT);
-
-static void
-on_tasks_changed (CalendarClient *client,
-                  gpointer        user_data)
-{
-  ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (user_data);
-  /* g_print ("on tasks changed\n"); */
-  g_signal_emit (source, signals[CHANGED_SIGNAL], 0);
-}
-
-static void
-on_appointments_changed (CalendarClient *client,
-                         gpointer        user_data)
-{
-  ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (user_data);
-  /* g_print ("on appointments changed\n"); */
-  g_signal_emit (source, signals[CHANGED_SIGNAL], 0);
-}
-
-static void
-shell_evolution_event_source_init (ShellEvolutionEventSource *source)
-{
-  source->client = calendar_client_new ();
-  g_signal_connect (source->client,
-                    "tasks-changed",
-                    G_CALLBACK (on_tasks_changed),
-                    source);
-  g_signal_connect (source->client,
-                    "appointments-changed",
-                    G_CALLBACK (on_appointments_changed),
-                    source);
-}
-
-static void
-shell_evolution_event_source_finalize (GObject *object)
-{
-  ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (object);
-  g_object_unref (source->client);
-  G_OBJECT_CLASS (shell_evolution_event_source_parent_class)->finalize (object);
-}
-
-static void
-shell_evolution_event_source_class_init (ShellEvolutionEventSourceClass *klass)
-{
-  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
-  gobject_class->finalize = shell_evolution_event_source_finalize;
-
-  signals[CHANGED_SIGNAL] =
-    g_signal_new ("changed",
-                  G_TYPE_FROM_CLASS (klass),
-                  G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL,
-                  g_cclosure_marshal_VOID__VOID,
-                  G_TYPE_NONE, 0);
-
-}
-
-ShellEvolutionEventSource *
-shell_evolution_event_source_new (void)
-{
-  return SHELL_EVOLUTION_EVENT_SOURCE (g_object_new (SHELL_TYPE_EVOLUTION_EVENT_SOURCE, NULL));
-}
-
-void
-shell_evolution_event_source_request_range (ShellEvolutionEventSource *source,
-                                            gint64                     msec_begin,
-                                            gint64                     msec_end)
-{
-  GDateTime *middle_utc, *middle;
-
-  /* The CalendarClient type is a convenience wrapper on top of
-   * Evolution Data Server. It is based on the assumption that only
-   * a single month is shown at a time.
-   *
-   * To avoid reimplemting all the work already done in CalendarClient
-   * we make the same assumption. This means that we only show events
-   * in the month that is in the middle of @msec_begin and
-   * @msec_end. Since the Shell displays a month at a time (plus the
-   * days before and after) it works out just fine.
-   */
-
-  middle_utc = g_date_time_new_from_unix_utc ((msec_begin + msec_end) / 2 / 1000);
-  /* CalendarClient uses localtime rather than UTC */
-  middle = g_date_time_to_local (middle_utc);
-  g_date_time_unref (middle_utc);
-  g_date_time_get_ymd (middle, &source->req_year, &source->req_mon, NULL);
-  g_date_time_unref (middle);
-  calendar_client_select_month (source->client, source->req_mon - 1, source->req_year);
-}
-
-static gint
-event_cmp (gconstpointer a,
-           gconstpointer b)
-{
-  const ShellEvolutionEvent *ea;
-  const ShellEvolutionEvent *eb;
-
-  ea = a;
-  eb = b;
-  if (ea->msec_begin < eb->msec_begin)
-    return -1;
-  else if (ea->msec_begin > eb->msec_begin)
-    return 1;
-  else
-    return 0;
-}
-
-/**
- * shell_evolution_event_source_get_events:
- * @source: A #ShellEvolutionEventSource.
- * @msec_begin: Start date (milli-seconds since Epoch).
- * @msec_end: End date (milli-seconds since Epoch).
- *
- * Gets all events that occur between @msec_begin and @msec_end.
- *
- * Returns: (element-type ShellEvolutionEvent) (transfer full): List of events.
- */
-GList *
-shell_evolution_event_source_get_events  (ShellEvolutionEventSource *source,
-                                          gint64                     msec_begin,
-                                          gint64                     msec_end)
-{
-  GList *result;
-  GDateTime *cur_date;
-  GDateTime *begin_date_utc, *begin_date;
-  GDateTime *end_date_utc, *end_date;
-
-  g_return_val_if_fail (msec_begin <= msec_end, NULL);
-
-  result = NULL;
-
-  begin_date_utc = g_date_time_new_from_unix_utc (msec_begin / 1000);
-  end_date_utc = g_date_time_new_from_unix_utc (msec_end / 1000);
-
-  /* CalendarClient uses localtime rather than UTC */
-  begin_date = g_date_time_to_local (begin_date_utc);
-  end_date = g_date_time_to_local (end_date_utc);
-  g_date_time_unref (begin_date_utc);
-  g_date_time_unref (end_date_utc);
-
-  cur_date = g_date_time_ref (begin_date);
-  do
-    {
-      gint year, mon, day;
-      GDateTime *next_date;
-
-      g_date_time_get_ymd (cur_date, &year, &mon, &day);
-      /* g_print ("y=%04d m=%02d d=%02d\n", year, mon, day); */
-
-      /* Silently drop events not in range (see comment in
-       * shell_evolution_event_source_request_range() above)
-       */
-      if (!(year == source->req_year && mon == source->req_mon))
-        {
-          /* g_print ("skipping day\n"); */
-        }
-      else
-        {
-          GSList *events;
-          GSList *l;
-          calendar_client_select_day (source->client, day);
-          events = calendar_client_get_events (source->client, CALENDAR_EVENT_APPOINTMENT);
-          /* g_print ("num_events: %d\n", g_slist_length (events)); */
-          for (l = events; l; l = l->next)
-            {
-              CalendarAppointment *appointment = l->data;
-              ShellEvolutionEvent *event;
-              gint64 start_time;
-
-              if (appointment->is_all_day)
-                {
-                  start_time = g_date_time_to_unix (cur_date) * G_GINT64_CONSTANT (1000);
-                }
-              else
-                {
-                  start_time = appointment->start_time * G_GINT64_CONSTANT (1000);
-                }
-              event = shell_evolution_event_new (appointment->summary,
-                                                 appointment->is_all_day,
-                                                 start_time);
-              result = g_list_prepend (result, event);
-            }
-          g_slist_foreach (events, (GFunc) calendar_event_free, NULL);
-          g_slist_free (events);
-        }
-
-      next_date = g_date_time_add_days (cur_date, 1);
-      g_date_time_unref (cur_date);
-      cur_date = next_date;
-    }
-  while (g_date_time_difference (end_date, cur_date) > 0);
-  g_date_time_unref (begin_date);
-  g_date_time_unref (end_date);
-
-  result = g_list_sort (result, event_cmp);
-
-  return result;
-}
-
-G_DEFINE_BOXED_TYPE (ShellEvolutionEvent,
-                     shell_evolution_event,
-                     shell_evolution_event_copy,
-                     shell_evolution_event_free);
-
-void
-shell_evolution_event_free (ShellEvolutionEvent *event)
-{
-  g_free (event->summary);
-  g_free (event);
-}
-
-ShellEvolutionEvent *
-shell_evolution_event_copy (ShellEvolutionEvent *event)
-{
-  ShellEvolutionEvent *copy;
-  copy = g_memdup (event, sizeof (ShellEvolutionEvent));
-  copy->summary = g_strdup (event->summary);
-  return copy;
-}
-
-ShellEvolutionEvent *
-shell_evolution_event_new (const gchar *summary,
-                           gboolean     all_day,
-                           gint64       msec_begin)
-{
-  ShellEvolutionEvent *event;
-  event = g_new0 (ShellEvolutionEvent, 1);
-  event->summary = g_strdup (summary);
-  event->all_day = all_day;
-  event->msec_begin = msec_begin;
-  return event;
-}
diff --git a/src/shell-evolution-event-source.h b/src/shell-evolution-event-source.h
deleted file mode 100644 (file)
index 4866b45..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-#ifndef __SHELL_EVOLUTION_EVENT_SOURCE_H__
-#define __SHELL_EVOLUTION_EVENT_SOURCE_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-typedef struct _ShellEvolutionEvent            ShellEvolutionEvent;
-
-struct _ShellEvolutionEvent
-{
-  gchar    *summary;
-  gboolean  all_day;
-  gint64    msec_begin;
-};
-
-GType                shell_evolution_event_get_type (void) G_GNUC_CONST;
-ShellEvolutionEvent *shell_evolution_event_new      (const gchar *summary,
-                                                     gboolean     all_day,
-                                                     gint64       msec_begin);
-ShellEvolutionEvent *shell_evolution_event_copy     (ShellEvolutionEvent *event);
-void                 shell_evolution_event_free     (ShellEvolutionEvent *event);
-
-typedef struct _ShellEvolutionEventSource      ShellEvolutionEventSource;
-typedef struct _ShellEvolutionEventSourceClass ShellEvolutionEventSourceClass;
-
-#define SHELL_TYPE_EVOLUTION_EVENT_SOURCE              (shell_evolution_event_source_get_type ())
-#define SHELL_EVOLUTION_EVENT_SOURCE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSource))
-#define SHELL_EVOLUTION_EVENT_SOURCE_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSourceClass))
-#define SHELL_IS_EVOLUTION_EVENT_SOURCE(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_EVOLUTION_EVENT_SOURCE))
-#define SHELL_IS_EVOLUTION_EVENT_SOURCE_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_EVOLUTION_EVENT_SOURCE))
-#define SHELL_EVOLUTION_EVENT_SOURCE_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSourceClass))
-
-GType                      shell_evolution_event_source_get_type      (void) G_GNUC_CONST;
-ShellEvolutionEventSource *shell_evolution_event_source_new           (void);
-void                       shell_evolution_event_source_request_range (ShellEvolutionEventSource *source,
-                                                                       gint64                     msec_begin,
-                                                                       gint64                     msec_end);
-GList                     *shell_evolution_event_source_get_events    (ShellEvolutionEventSource *source,
-                                                                       gint64                     msec_begin,
-                                                                       gint64                     msec_end);
-G_END_DECLS
-
-#endif /* __SHELL_EVOLUTION_EVENT_SOURCE_H__ */
index f42237e63804e211559729b54049cb152d956167..4f08bcaab0aebdc7337a063284cb070ee62787d1 100644 (file)
@@ -1984,3 +1984,57 @@ shell_get_tp_contacts (TpConnection *self,
                                        shell_global_get_tp_contacts_cb,
                                        callback, NULL, NULL);
 }
+
+/**
+ * shell_global_launch_calendar_server:
+ * @global: The #ShellGlobal.
+ *
+ * Launch the gnome-shell-calendar-server helper.
+ */
+void
+shell_global_launch_calendar_server (ShellGlobal *global)
+{
+  const gchar *bin_dir;
+  gchar *calendar_server_exe;
+  GError *error;
+  gchar *argv[2];
+  gint child_standard_input;
+
+  /* launch calendar-server */
+  bin_dir = g_getenv ("GNOME_SHELL_BINDIR");
+  if (bin_dir != NULL)
+    calendar_server_exe = g_strdup_printf ("%s/gnome-shell-calendar-server", bin_dir);
+  else
+    calendar_server_exe = g_strdup_printf (GNOME_SHELL_LIBEXECDIR "/gnome-shell-calendar-server");
+
+  argv[0] = calendar_server_exe;
+  argv[1] = NULL;
+  error = NULL;
+  if (!g_spawn_async_with_pipes (NULL, /* working_directory */
+                                 argv,
+                                 NULL, /* envp */
+                                 0, /* GSpawnFlags */
+                                 NULL, /* child_setup */
+                                 NULL, /* user_data */
+                                 NULL, /* GPid *child_pid */
+                                 &child_standard_input,
+                                 NULL, /* gint *stdout */
+                                 NULL, /* gint *stderr */
+                                 &error))
+    {
+      g_warning ("Error launching `%s': %s (%s %d)",
+                 calendar_server_exe,
+                 error->message,
+                 g_quark_to_string (error->domain),
+                 error->code);
+      g_error_free (error);
+    }
+  /* Note that gnome-shell-calendar-server exits whenever its stdin
+   * file descriptor is HUP'ed. This means that whenever the the shell
+   * process exits or is being replaced, the calendar server is also
+   * exits...and if the shell is being replaced, a new copy of the
+   * calendar server is launched...
+   */
+
+  g_free (calendar_server_exe);
+}
index 0adb32c25aa2463deb8acbbd04a2287b665acafb..66b9127355bd061c1b13bd6ecbad7de0403e2419 100644 (file)
@@ -156,6 +156,8 @@ void shell_get_tp_contacts (TpConnection *self,
                             const TpContactFeature *features,
                             ShellGetTpContactCb callback);
 
+void shell_global_launch_calendar_server (ShellGlobal *global);
+
 G_END_DECLS
 
 #endif /* __SHELL_GLOBAL_H__ */